summaryrefslogtreecommitdiff
path: root/mozilla/security/nss/lib/freebl/ecl
diff options
context:
space:
mode:
Diffstat (limited to 'mozilla/security/nss/lib/freebl/ecl')
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/Makefile230
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/README330
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/README.FP317
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ec2.h126
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ec2_163.c259
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ec2_193.c276
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ec2_233.c299
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ec2_aff.c346
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ec2_mont.c274
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ec2_proj.c369
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ec_naf.c103
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecl-curve.h144
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecl-exp.h196
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecl-priv.h281
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecl.c429
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecl.h91
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecl_curve.c123
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecl_gf.c1032
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecl_mult.c356
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecp.h140
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecp_192.c516
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecp_224.c372
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecp_256.c429
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecp_384.c293
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecp_521.c170
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecp_aff.c357
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecp_fp.c568
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecp_fp.h406
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecp_fp160.c179
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecp_fp192.c177
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecp_fp224.c190
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecp_fpinc.c855
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecp_jac.c553
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecp_jm.c323
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/ecp_mont.c192
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/tests/ec2_test.c516
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/tests/ec_naft.c151
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/tests/ecp_fpt.c1123
-rw-r--r--mozilla/security/nss/lib/freebl/ecl/tests/ecp_test.c460
39 files changed, 13551 insertions, 0 deletions
diff --git a/mozilla/security/nss/lib/freebl/ecl/Makefile b/mozilla/security/nss/lib/freebl/ecl/Makefile
new file mode 100644
index 0000000..9ada3eb
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/Makefile
@@ -0,0 +1,230 @@
+#
+# Makefile for elliptic curve library
+
+# ***** BEGIN LICENSE BLOCK *****
+# 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>
+# Michael J. Fromberger <sting@linguist.dartmouth.edu>
+# Netscape Communications Corporation
+# Richard C. Swift (swift@netscape.com)
+#
+# 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.
+#
+# ***** END LICENSE BLOCK *****
+
+## Define CC to be the C compiler you wish to use. The GNU cc
+## compiler (gcc) should work, at the very least
+#CC=cc
+#CC=gcc
+
+##
+## Define PERL to point to your local Perl interpreter. It
+## should be Perl 5.x, although it's conceivable that Perl 4
+## might work ... I haven't tested it.
+##
+#PERL=/usr/bin/perl
+#PERL=perl
+
+include ../mpi/target.mk
+
+##
+## Define platform-dependent variables for use of floating-point code.
+##
+ifeq ($(TARGET),v9SOLARIS)
+ECL_USE_FP=1
+else
+ifeq ($(TARGET),v8plusSOLARIS)
+ECL_USE_FP=1
+else
+ifeq ($(TARGET),v8SOLARIS)
+ECL_USE_FP=1
+else
+ifeq ($(TARGET),x86LINUX)
+ECL_USE_FP=1
+endif
+endif
+endif
+endif
+
+##
+## Add to definition of CFLAGS depending on use of floating-point code.
+##
+ifeq ($(ECL_USE_FP),1)
+CFLAGS+= -DECL_USE_FP
+endif
+
+##
+## Define LIBS to include any libraries you need to link against.
+## If NO_TABLE is define, LIBS should include '-lm' or whatever is
+## necessary to bring in the math library. Otherwise, it can be
+## left alone, unless your system has other peculiar requirements.
+##
+LIBS=-L../mpi -lmpi -lm#-lmalloc#-lefence
+
+##
+## Define INCLUDES to include any include directories you need to
+## compile with.
+##
+INCLUDES=-I../mpi
+CFLAGS+= $(INCLUDES) $(XCFLAGS)
+
+##
+## Define RANLIB to be the library header randomizer; you might not
+## need this on some systems (just set it to 'echo' on these systems,
+## such as IRIX)
+##
+RANLIB=echo
+
+##
+## Define LIBOBJS to be the object files that will be created during
+## the build process.
+##
+LIBOBJS = ecl.o ecl_curve.o ecl_mult.o ecl_gf.o \
+ ec2_aff.o ec2_mont.o ec2_proj.o \
+ ec2_163.o ec2_193.o ec2_233.o \
+ ecp_aff.o ecp_jac.o ecp_mont.o \
+ ec_naf.o ecp_jm.o \
+ ecp_192.o ecp_224.o ecp_256.o ecp_384.o ecp_521.o
+ifeq ($(ECL_USE_FP),1)
+LIBOBJS+= ecp_fp160.o ecp_fp192.o ecp_fp224.o ecp_fp.o
+endif
+
+## The headers contained in this library.
+LIBHDRS = ecl-exp.h ecl.h ec2.h ecp.h ecl-priv.h ecl-curve.h
+APPHDRS = ecl-exp.h ecl.h ec2.h ecp.h ecl-priv.h ecl-curve.h
+ifeq ($(ECL_GFP_ASSEMBLY_FP),1)
+LIBHDRS += ecp_fp.h
+APPHDRS += ecp_fp.h
+endif
+
+
+help:
+ @ echo ""
+ @ echo "The following targets can be built with this Makefile:"
+ @ echo ""
+ @ echo "libecl.a - elliptic curve library"
+ @ echo "tests - build command line tests"
+ @ echo "test - run command line tests"
+ @ echo "clean - clean up objects and such"
+ @ echo ""
+
+.SUFFIXES: .c .o .i
+
+.c.i:
+ $(CC) $(CFLAGS) -E $< > $@
+
+#---------------------------------------
+
+$(LIBOBJS): $(LIBHDRS)
+
+ecl.o: ecl.c $(LIBHDRS)
+ecl_curve.o: ecl_curve.c $(LIBHDRS)
+ecl_mult.o: ecl_mult.c $(LIBHDRS)
+ecl_gf.o: ecl_gf.c $(LIBHDRS)
+ec2_aff.o: ec2_aff.c $(LIBHDRS)
+ec2_mont.o: ec2_mont.c $(LIBHDRS)
+ec2_proj.o: ec2_proj.c $(LIBHDRS)
+ec2_163.o: ec2_163.c $(LIBHDRS)
+ec2_193.o: ec2_193.c $(LIBHDRS)
+ec2_233.o: ec2_233.c $(LIBHDRS)
+ecp_aff.o: ecp_aff.c $(LIBHDRS)
+ecp_jac.o: ecp_jac.c $(LIBHDRS)
+ecp_jm.o: ecp_jm.c $(LIBHDRS)
+ecp_mont.o: ecp_mont.c $(LIBHDRS)
+ecp_192.o: ecp_192.c $(LIBHDRS)
+ecp_224.o: ecp_224.c $(LIBHDRS)
+ecp_256.o: ecp_256.c $(LIBHDRS)
+ecp_384.o: ecp_384.c $(LIBHDRS)
+ecp_521.o: ecp_521.c $(LIBHDRS)
+ecp_fp.o: ecp_fp.c $(LIBHDRS)
+ifeq ($(ECL_USE_FP),1)
+ecp_fp160.o: ecp_fp160.c ecp_fpinc.c $(LIBHDRS)
+ecp_fp192.o: ecp_fp192.c ecp_fpinc.c $(LIBHDRS)
+ecp_fp224.o: ecp_fp224.c ecp_fpinc.c $(LIBHDRS)
+endif
+
+libecl.a: $(LIBOBJS)
+ ar -cvr libecl.a $(LIBOBJS)
+ $(RANLIB) libecl.a
+
+lib libs: libecl.a
+
+ecl.i: ecl.h
+
+#---------------------------------------
+
+ECLTESTOBJS = ec2_test.o ecp_test.o ec_naft.o
+ifeq ($(ECL_USE_FP),1)
+ECLTESTOBJS+= ecp_fpt.o
+endif
+ECLTESTS = $(ECLTESTOBJS:.o=)
+
+$(ECLTESTOBJS): %.o: tests/%.c $(LIBHDRS)
+ $(CC) $(CFLAGS) -o $@ -c $< $(INCLUDES)
+
+$(ECLTESTS): %: %.o libecl.a
+ $(CC) $(CFLAGS) -o $@ $^ $(LIBS)
+
+ifeq ($(ECL_USE_FP),1)
+tests: ec2_test ecp_test ec_naft ecp_fpt
+else
+tests: ec2_test ecp_test ec_naft
+endif
+
+#---------------------------------------
+
+ifeq ($(ECL_USE_FP),1)
+test: tests
+ ./ecp_test
+ ./ec2_test
+ ./ec_naft
+ ./ecp_fpt
+else
+test: tests
+ ./ecp_test
+ ./ec_naft
+ ./ec2_test
+endif
+
+#---------------------------------------
+
+alltests: tests
+
+clean:
+ rm -f *.o *.a *.i
+ rm -f core
+ rm -f *~ .*~
+ rm -f $(ECLTESTS)
+
+clobber: clean
+
+# END
diff --git a/mozilla/security/nss/lib/freebl/ecl/README b/mozilla/security/nss/lib/freebl/ecl/README
new file mode 100644
index 0000000..b4c9240
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/README
@@ -0,0 +1,330 @@
+***** BEGIN LICENSE BLOCK *****
+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 Sun Microsystems, Inc. are Copyright (C) 2003
+Sun Microsystems, Inc. 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.
+
+***** END LICENSE BLOCK *****
+
+The ECL exposes routines for constructing and converting curve
+parameters for internal use.
+
+
+HEADER FILES
+============
+
+ecl-exp.h - Exports data structures and curve names. For use by code
+that does not have access to mp_ints.
+
+ecl-curve.h - Provides hex encodings (in the form of ECCurveParams
+structs) of standardizes elliptic curve domain parameters and mappings
+from ECCurveName to ECCurveParams. For use by code that does not have
+access to mp_ints.
+
+ecl.h - Interface to constructors for curve parameters and group object,
+and point multiplication operations. Used by higher level algorithms
+(like ECDH and ECDSA) to actually perform elliptic curve cryptography.
+
+ecl-priv.h - Data structures and functions for internal use within the
+library.
+
+ec2.h - Internal header file that contains all functions for point
+arithmetic over binary polynomial fields.
+
+ecp.h - Internal header file that contains all functions for point
+arithmetic over prime fields.
+
+DATA STRUCTURES AND TYPES
+=========================
+
+ECCurveName (from ecl-exp.h) - Opaque name for standardized elliptic
+curve domain parameters.
+
+ECCurveParams (from ecl-exp.h) - Provides hexadecimal encoding
+of elliptic curve domain parameters. Can be generated by a user
+and passed to ECGroup_fromHex or can be generated from a name by
+EC_GetNamedCurveParams. ecl-curve.h contains ECCurveParams structs for
+the standardized curves defined by ECCurveName.
+
+ECGroup (from ecl.h and ecl-priv.h) - Opaque data structure that
+represents a group of elliptic curve points for a particular set of
+elliptic curve domain parameters. Contains all domain parameters (curve
+a and b, field, base point) as well as pointers to the functions that
+should be used for point arithmetic and the underlying field GFMethod.
+Generated by either ECGroup_fromHex or ECGroup_fromName.
+
+GFMethod (from ecl-priv.h) - Represents a field underlying a set of
+elliptic curve domain parameters. Contains the irreducible that defines
+the field (either the prime or the binary polynomial) as well as
+pointers to the functions that should be used for field arithmetic.
+
+ARITHMETIC FUNCTIONS
+====================
+
+Higher-level algorithms (like ECDH and ECDSA) should call ECPoint_mul
+or ECPoints_mul (from ecl.h) to do point arithmetic. These functions
+will choose which underlying algorithms to use, based on the ECGroup
+structure.
+
+Point Multiplication
+--------------------
+
+ecl_mult.c provides the ECPoints_mul and ECPoint_mul wrappers.
+It also provides two implementations for the pts_mul operation -
+ec_pts_mul_basic (which computes kP, lQ, and then adds kP + lQ) and
+ec_pts_mul_simul_w2 (which does a simultaneous point multiplication
+using a table with window size 2*2).
+
+ec_naf.c provides an implementation of an algorithm to calculate a
+non-adjacent form of a scalar, minimizing the number of point
+additions that need to be done in a point multiplication.
+
+Point Arithmetic over Prime Fields
+----------------------------------
+
+ecp_aff.c provides point arithmetic using affine coordinates.
+
+ecp_jac.c provides point arithmetic using Jacobian projective
+coordinates and mixed Jacobian-affine coordinates. (Jacobian projective
+coordinates represent a point (x, y) as (X, Y, Z), where x=X/Z^2,
+y=Y/Z^3).
+
+ecp_jm.c provides point arithmetic using Modified Jacobian
+coordinates and mixed Modified_Jacobian-affine coordinates.
+(Modified Jacobian coordinates represent a point (x, y)
+as (X, Y, Z, a*Z^4), where x=X/Z^2, y=Y/Z^3, and a is
+the linear coefficient in the curve defining equation).
+
+ecp_192.c and ecp_224.c provide optimized field arithmetic.
+
+Point Arithmetic over Binary Polynomial Fields
+----------------------------------------------
+
+ec2_aff.c provides point arithmetic using affine coordinates.
+
+ec2_proj.c provides point arithmetic using projective coordinates.
+(Projective coordinates represent a point (x, y) as (X, Y, Z), where
+x=X/Z, y=Y/Z^2).
+
+ec2_mont.c provides point multiplication using Montgomery projective
+coordinates.
+
+ec2_163.c, ec2_193.c, and ec2_233.c provide optimized field arithmetic.
+
+Field Arithmetic
+----------------
+
+ecl_gf.c provides constructors for field objects (GFMethod) with the
+functions GFMethod_cons*. It also provides wrappers around the basic
+field operations.
+
+Prime Field Arithmetic
+----------------------
+
+The mpi library provides the basic prime field arithmetic.
+
+ecp_mont.c provides wrappers around the Montgomery multiplication
+functions from the mpi library and adds encoding and decoding functions.
+It also provides the function to construct a GFMethod object using
+Montgomery multiplication.
+
+ecp_192.c and ecp_224.c provide optimized modular reduction for the
+fields defined by nistp192 and nistp224 primes.
+
+ecl_gf.c provides wrappers around the basic field operations.
+
+Binary Polynomial Field Arithmetic
+----------------------------------
+
+../mpi/mp_gf2m.c provides basic binary polynomial field arithmetic,
+including addition, multiplication, squaring, mod, and division, as well
+as conversion ob polynomial representations between bitstring and int[].
+
+ec2_163.c, ec2_193.c, and ec2_233.c provide optimized field mod, mul,
+and sqr operations.
+
+ecl_gf.c provides wrappers around the basic field operations.
+
+Field Encoding
+--------------
+
+By default, field elements are encoded in their basic form. It is
+possible to use an alternative encoding, however. For example, it is
+possible to Montgomery representation of prime field elements and
+take advantage of the fast modular multiplication that Montgomery
+representation provides. The process of converting from basic form to
+Montgomery representation is called field encoding, and the opposite
+process would be field decoding. All internal point operations assume
+that the operands are field encoded as appropriate. By rewiring the
+underlying field arithmetic to perform operations on these encoded
+values, the same overlying point arithmetic operations can be used
+regardless of field representation.
+
+ALGORITHM WIRING
+================
+
+The EC library allows point and field arithmetic algorithms to be
+substituted ("wired-in") on a fine-grained basis. This allows for
+generic algorithms and algorithms that are optimized for a particular
+curve, field, or architecture, to coexist and to be automatically
+selected at runtime.
+
+Wiring Mechanism
+----------------
+
+The ECGroup and GFMethod structure contain pointers to the point and
+field arithmetic functions, respectively, that are to be used in
+operations.
+
+The selection of algorithms to use is handled in the function
+ecgroup_fromNameAndHex in ecl.c.
+
+Default Wiring
+--------------
+
+Curves over prime fields by default use montgomery field arithmetic,
+point multiplication using 5-bit window non-adjacent-form with
+Modified Jacobian coordinates, and 2*2-bit simultaneous point
+multiplication using Jacobian coordinates.
+(Wiring in function ECGroup_consGFp_mont in ecl.c.)
+
+Curves over prime fields that have optimized modular reduction (i.e.,
+secp160r1, nistp192, and nistp224) do not use Montgomery field
+arithmetic. Instead, they use basic field arithmetic with their
+optimized reduction (as in ecp_192.c and ecp_224.c). They
+use the same point multiplication and simultaneous point multiplication
+algorithms as other curves over prime fields.
+
+Curves over binary polynomial fields by default use generic field
+arithmetic with montgomery point multiplication and basic kP + lQ
+computation (multiply, multiply, and add). (Wiring in function
+ECGroup_cons_GF2m in ecl.c.)
+
+Curves over binary polynomial fields that have optimized field
+arithmetic (i.e., any 163-, 193, or 233-bit field) use their optimized
+field arithmetic. They use the same point multiplication and
+simultaneous point multiplication algorithms as other curves over binary
+fields.
+
+Example
+-------
+
+We provide an example for plugging in an optimized implementation for
+the Koblitz curve nistk163.
+
+Suppose the file ec2_k163.c contains the optimized implementation. In
+particular it contains a point multiplication function:
+
+ mp_err ec_GF2m_nistk163_pt_mul(const mp_int *n, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry, const ECGroup *group);
+
+Since only a pt_mul function is provided, the generic pt_add function
+will be used.
+
+There are two options for handling the optimized field arithmetic used
+by the ..._pt_mul function. Say the optimized field arithmetic includes
+the following functions:
+
+ mp_err ec_GF2m_nistk163_add(const mp_int *a, const mp_int *b,
+ mp_int *r, const GFMethod *meth);
+ mp_err ec_GF2m_nistk163_mul(const mp_int *a, const mp_int *b,
+ mp_int *r, const GFMethod *meth);
+ mp_err ec_GF2m_nistk163_sqr(const mp_int *a, const mp_int *b,
+ mp_int *r, const GFMethod *meth);
+ mp_err ec_GF2m_nistk163_div(const mp_int *a, const mp_int *b,
+ mp_int *r, const GFMethod *meth);
+
+First, the optimized field arithmetic could simply be called directly
+by the ..._pt_mul function. This would be accomplished by changing
+the ecgroup_fromNameAndHex function in ecl.c to include the following
+statements:
+
+ if (name == ECCurve_NIST_K163) {
+ group = ECGroup_consGF2m(&irr, NULL, &curvea, &curveb, &genx,
+ &geny, &order, params->cofactor);
+ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+ MP_CHECKOK( ec_group_set_nistk163(group) );
+ }
+
+and including in ec2_k163.c the following function:
+
+ mp_err ec_group_set_nistk163(ECGroup *group) {
+ group->point_mul = &ec_GF2m_nistk163_pt_mul;
+ return MP_OKAY;
+ }
+
+As a result, ec_GF2m_pt_add and similar functions would use the
+basic binary polynomial field arithmetic ec_GF2m_add, ec_GF2m_mul,
+ec_GF2m_sqr, and ec_GF2m_div.
+
+Alternatively, the optimized field arithmetic could be wired into the
+group's GFMethod. This would be accomplished by putting the following
+function in ec2_k163.c:
+
+ mp_err ec_group_set_nistk163(ECGroup *group) {
+ group->meth->field_add = &ec_GF2m_nistk163_add;
+ group->meth->field_mul = &ec_GF2m_nistk163_mul;
+ group->meth->field_sqr = &ec_GF2m_nistk163_sqr;
+ group->meth->field_div = &ec_GF2m_nistk163_div;
+ group->point_mul = &ec_GF2m_nistk163_pt_mul;
+ return MP_OKAY;
+ }
+
+For an example of functions that use special field encodings, take a
+look at ecp_mont.c.
+
+TESTING
+=======
+
+The ecl/tests directory contains a collection of standalone tests that
+verify the correctness of the elliptic curve library.
+
+Both ecp_test and ec2_test take the following arguments:
+
+ --print Print out results of each point arithmetic test.
+ --time Benchmark point operations and print results.
+
+The set of curves over which ecp_test and ec2_test run is coded into the
+program, but can be changed by editing the source files.
+
+BUILDING
+========
+
+The ecl can be built as a standalone library, separate from NSS,
+dependent only on the mpi library. To build the library:
+
+ > cd ../mpi
+ > make libs
+ > cd ../ecl
+ > make libs
+ > make tests # to build test files
+ > make test # to run automated tests
diff --git a/mozilla/security/nss/lib/freebl/ecl/README.FP b/mozilla/security/nss/lib/freebl/ecl/README.FP
new file mode 100644
index 0000000..858ac67
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/README.FP
@@ -0,0 +1,317 @@
+***** BEGIN LICENSE BLOCK *****
+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 Sun Microsystems, Inc. are Copyright (C) 2003
+Sun Microsystems, Inc. All Rights Reserved.
+
+Contributor(s):
+ Stephen Fung <fungstep@hotmail.com> and
+ Nils Gura <nils.gura@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.
+
+***** END LICENSE BLOCK *****
+
+The ECL exposes routines for constructing and converting curve
+parameters for internal use.
+
+The floating point code of the ECL provides algorithms for performing
+elliptic-curve point multiplications in floating point.
+
+The point multiplication algorithms perform calculations almost
+exclusively in floating point for efficiency, but have the same
+(integer) interface as the ECL for compatibility and to be easily
+wired-in to the ECL. Please see README file (not this README.FP file)
+for information on wiring-in.
+
+This has been implemented for 3 curves as specified in [1]:
+ secp160r1
+ secp192r1
+ secp224r1
+
+RATIONALE
+=========
+Calculations are done in the floating-point unit (FPU) since it
+gives better performance on the UltraSPARC III chips. This is
+because the FPU allows for faster multiplication than the integer unit.
+The integer unit has a longer multiplication instruction latency, and
+does not allow full pipelining, as described in [2].
+Since performance is an important selling feature of Elliptic Curve
+Cryptography (ECC), this implementation was created.
+
+DATA REPRESENTATION
+===================
+Data is primarily represented in an array of double-precision floating
+point numbers. Generally, each array element has 24 bits of precision
+(i.e. be x * 2^y, where x is an integer of at most 24 bits, y some positive
+integer), although the actual implementation details are more complicated.
+
+e.g. a way to store an 80 bit number might be:
+double p[4] = { 632613 * 2^0, 329841 * 2^24, 9961 * 2^48, 51 * 2^64 };
+See section ARITHMETIC OPERATIONS for more details.
+
+This implementation assumes that the floating-point unit rounding mode
+is round-to-even as specified in IEEE 754
+(as opposed to chopping, rounding up, or rounding down).
+When subtracting integers represented as arrays of floating point
+numbers, some coefficients (array elements) may become negative.
+This effectively gives an extra bit of precision that is important
+for correctness in some cases.
+
+The described number presentation limits the size of integers to 1023 bits.
+This is due to an upper bound of 1024 for the exponent of a double precision
+floating point number as specified in IEEE-754.
+However, this is acceptable for ECC key sizes of the foreseeable future.
+
+DATA STRUCTURES
+===============
+For more information on coordinate representations, see [3].
+
+ecfp_aff_pt
+-----------
+Affine EC Point Representation. This is the basic
+representation (x, y) of an elliptic curve point.
+
+ecfp_jac_pt
+-----------
+Jacobian EC Point. This stores a point as (X, Y, Z), where
+the affine point corresponds to (X/Z^2, Y/Z^3). This allows
+for fewer inversions in calculations.
+
+ecfp_chud_pt
+------------
+Chudnovsky Jacobian Point. This representation stores a point
+as (X, Y, Z, Z^2, Z^3), the same as a Jacobian representation
+but also storing Z^2 and Z^3 for faster point additions.
+
+ecfp_jm_pt
+----------
+Modified Jacobian Point. This representation stores a point
+as (X, Y, Z, a*Z^4), the same as Jacobian representation but
+also storing a*Z^4 for faster point doublings. Here "a" represents
+the linear coefficient of x defining the curve.
+
+EC_group_fp
+-----------
+Stores information on the elliptic curve group for floating
+point calculations. Contains curve specific information, as
+well as function pointers to routines, allowing different
+optimizations to be easily wired in.
+This should be made accessible from an ECGroup for the floating
+point implementations of point multiplication.
+
+POINT MULTIPLICATION ALGORITHMS
+===============================
+Elliptic Curve Point multiplication can be done at a higher level orthogonal
+to the implementation of point additions and point doublings. There
+are a variety of algorithms that can be used.
+
+The following algorithms have been implemented:
+
+4-bit Window (Jacobian Coordinates)
+Double & Add (Jacobian & Affine Coordinates)
+5-bit Non-Adjacent Form (Modified Jacobian & Chudnovsky Jacobian)
+
+Currently, the fastest algorithm for multiplying a generic point
+is the 5-bit Non-Adjacent Form.
+
+See comments in ecp_fp.c for more details and references.
+
+SOURCE / HEADER FILES
+=====================
+
+ecp_fp.c
+--------
+Main source file for floating point calculations. Contains routines
+to convert from floating-point to integer (mp_int format), point
+multiplication algorithms, and several other routines.
+
+ecp_fp.h
+--------
+Main header file. Contains most constants used and function prototypes.
+
+ecp_fp[160, 192, 224].c
+-----------------------
+Source files for specific curves. Contains curve specific code such
+as specialized reduction based on the field defining prime. Contains
+code wiring-in different algorithms and optimizations.
+
+ecp_fpinc.c
+-----------
+Source file that is included by ecp_fp[160, 192, 224].c. This generates
+functions with different preprocessor-defined names and loop iterations,
+allowing for static linking and strong compiler optimizations without
+code duplication.
+
+TESTING
+=======
+The test suite can be found in ecl/tests/ecp_fpt. This tests and gets
+timings of the different algorithms for the curves implemented.
+
+ARITHMETIC OPERATIONS
+---------------------
+The primary operations in ECC over the prime fields are modular arithmetic:
+i.e. n * m (mod p) and n + m (mod p). In this implementation, multiplication,
+addition, and reduction are implemented as separate functions. This
+enables computation of formulae with fewer reductions, e.g.
+(a * b) + (c * d) (mod p) rather than:
+((a * b) (mod p)) + ((c * d) (mod p)) (mod p)
+This takes advantage of the fact that the double precision mantissa in
+floating point can hold numbers up to 2^53, i.e. it has some leeway to
+store larger intermediate numbers. See further detail in the section on
+FLOATING POINT PRECISION.
+
+Multiplication
+--------------
+Multiplication is implemented in a standard polynomial multiplication
+fashion. The terms in opposite factors are pairwise multiplied and
+added together appropriately. Note that the result requires twice
+as many doubles for storage, as the bit size of the product is twice
+that of the multiplicands.
+e.g. suppose we have double n[3], m[3], r[6], and want to calculate r = n * m
+r[0] = n[0] * m[0]
+r[1] = n[0] * m[1] + n[1] * m[0]
+r[2] = n[0] * m[2] + n[1] * m[1] + n[2] * m[0]
+r[3] = n[1] * m[2] + n[2] * m[1]
+r[4] = n[2] * m[2]
+r[5] = 0 (This is used later to hold spillover from r[4], see tidying in
+the reduction section.)
+
+Addition
+--------
+Addition is done term by term. The only caveat is to be careful with
+the number of terms that need to be added. When adding results of
+multiplication (before reduction), twice as many terms need to be added
+together. This is done in the addLong function.
+e.g. for double n[4], m[4], r[4]: r = n + m
+r[0] = n[0] + m[0]
+r[1] = n[1] + m[1]
+r[2] = n[2] + m[2]
+r[3] = n[3] + m[3]
+
+Modular Reduction
+-----------------
+For the curves implemented, reduction is possible by fast reduction
+for Generalized Mersenne Primes, as described in [4]. For the
+floating point implementation, a significant step of the reduction
+process is tidying: that is, the propagation of carry bits from
+low-order to high-order coefficients to reduce the precision of each
+coefficient to 24 bits.
+This is done by adding and then subtracting
+ecfp_alpha, a large floating point number that induces precision roundoff.
+See [5] for more details on tidying using floating point arithmetic.
+e.g. suppose we have r = 961838 * 2^24 + 519308
+then if we set alpha = 3 * 2^51 * 2^24,
+FP(FP(r + alpha) - alpha) = 961838 * 2^24, because the precision for
+the intermediate results is limited. Our values of alpha are chosen
+to truncate to a desired number of bits.
+
+The reduction is then performed as in [4], adding multiples of prime p.
+e.g. suppose we are working over a polynomial of 10^2. Take the number
+2 * 10^8 + 11 * 10^6 + 53 * 10^4 + 23 * 10^2 + 95, stored in 5 elements
+for coefficients of 10^0, 10^2, ..., 10^8.
+We wish to reduce modulo p = 10^6 - 2 * 10^4 + 1
+We can subtract off from the higher terms
+(2 * 10^8 + 11 * 10^6 + 53 * 10^4 + 23 * 10^2 + 95) - (2 * 10^2) * (10^6 - 2 * 10^4 + 1)
+= 15 * 10^6 + 53 * 10^4 + 21 * 10^2 + 95
+= 15 * 10^6 + 53 * 10^4 + 21 * 10^2 + 95 - (15) * (10^6 - 2 * 10^4 + 1)
+= 83 * 10^4 + 21 * 10^2 + 80
+
+Integrated Example
+------------------
+This example shows how multiplication, addition, tidying, and reduction
+work together in our modular arithmetic. This is simplified from the
+actual implementation, but should convey the main concepts.
+Working over polynomials of 10^2 and with p as in the prior example,
+Let a = 16 * 10^4 + 53 * 10^2 + 33
+let b = 81 * 10^4 + 31 * 10^2 + 49
+let c = 22 * 10^4 + 0 * 10^2 + 95
+And suppose we want to compute a * b + c mod p.
+We first do a multiplication: then a * b =
+0 * 10^10 + 1296 * 10^8 + 4789 * 10^6 + 5100 * 10^4 + 3620 * 10^2 + 1617
+Then we add in c before doing reduction, allowing us to get a * b + c =
+0 * 10^10 + 1296 * 10^8 + 4789 * 10^6 + 5122 * 10^4 + 3620 * 10^2 + 1712
+We then perform a tidying on the upper half of the terms:
+0 * 10^10 + 1296 * 10^8 + 4789 * 10^6
+0 * 10^10 + (1296 + 47) * 10^8 + 89 * 10^6
+0 * 10^10 + 1343 * 10^8 + 89 * 10^6
+13 * 10^10 + 43 * 10^8 + 89 * 10^6
+which then gives us
+13 * 10^10 + 43 * 10^8 + 89 * 10^6 + 5122 * 10^4 + 3620 * 10^2 + 1712
+we then reduce modulo p similar to the reduction example above:
+13 * 10^10 + 43 * 10^8 + 89 * 10^6 + 5122 * 10^4 + 3620 * 10^2 + 1712
+ - (13 * 10^4 * p)
+69 * 10^8 + 89 * 10^6 + 5109 * 10^4 + 3620 * 10^2 + 1712
+ - (69 * 10^2 * p)
+227 * 10^6 + 5109 * 10^4 + 3551 * 10^2 + 1712
+ - (227 * p)
+5563 * 10^4 + 3551 * 10^2 + 1485
+finally, we do tidying to get the precision of each term down to 2 digits
+5563 * 10^4 + 3565 * 10^2 + 85
+5598 * 10^4 + 65 * 10^2 + 85
+55 * 10^6 + 98 * 10^4 + 65 * 10^2 + 85
+and perform another reduction step
+ - (55 * p)
+208 * 10^4 + 65 * 10^2 + 30
+There may be a small number of further reductions that could be done at
+this point, but this is typically done only at the end when converting
+from floating point to an integer unit representation.
+
+FLOATING POINT PRECISION
+========================
+This section discusses the precision of floating point numbers, which
+one writing new formulae or a larger bit size should be aware of. The
+danger is that an intermediate result may be required to store a
+mantissa larger than 53 bits, which would cause error by rounding off.
+
+Note that the tidying with IEEE rounding mode set to round-to-even
+allows negative numbers, which actually reduces the size of the double
+mantissa to 23 bits - since it rounds the mantissa to the nearest number
+modulo 2^24, i.e. roughly between -2^23 and 2^23.
+A multiplication increases the bit size to 2^46 * n, where n is the number
+of doubles to store a number. For the 224 bit curve, n = 10. This gives
+doubles of size 5 * 2^47. Adding two of these doubles gives a result
+of size 5 * 2^48, which is less than 2^53, so this is safe.
+Similar analysis can be done for other formulae to ensure numbers remain
+below 2^53.
+
+Extended-Precision Floating Point
+---------------------------------
+Some platforms, notably x86 Linux, may use an extended-precision floating
+point representation that has a 64-bit mantissa. [6] Although this
+implementation is optimized for the IEEE standard 53-bit mantissa,
+it should work with the 64-bit mantissa. A check is done at run-time
+in the function ec_set_fp_precision that detects if the precision is
+greater than 53 bits, and runs code for the 64-bit mantissa accordingly.
+
+REFERENCES
+==========
+[1] Certicom Corp., "SEC 2: Recommended Elliptic Curve Domain Parameters", Sept. 20, 2000. www.secg.org
+[2] Sun Microsystems Inc. UltraSPARC III Cu User's Manual, Version 1.0, May 2002, Table 4.4
+[3] H. Cohen, A. Miyaji, and T. Ono, "Efficient Elliptic Curve Exponentiation Using Mixed Coordinates".
+[4] Henk C.A. van Tilborg, Generalized Mersenne Prime. http://www.win.tue.nl/~henkvt/GenMersenne.pdf
+[5] Daniel J. Bernstein, Floating-Point Arithmetic and Message Authentication, Journal of Cryptology, March 2000, Section 2.
+[6] Daniel J. Bernstein, Floating-Point Arithmetic and Message Authentication, Journal of Cryptology, March 2000, Section 2 Notes.
diff --git a/mozilla/security/nss/lib/freebl/ecl/ec2.h b/mozilla/security/nss/lib/freebl/ecl/ec2.h
new file mode 100644
index 0000000..2ca8418
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ec2.h
@@ -0,0 +1,126 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __ec2_h_
+#define __ec2_h_
+
+#include "ecl-priv.h"
+
+/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */
+mp_err ec_GF2m_pt_is_inf_aff(const mp_int *px, const mp_int *py);
+
+/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */
+mp_err ec_GF2m_pt_set_inf_aff(mp_int *px, mp_int *py);
+
+/* Computes R = P + Q where R is (rx, ry), P is (px, py) and Q is (qx,
+ * qy). Uses affine coordinates. */
+mp_err ec_GF2m_pt_add_aff(const mp_int *px, const mp_int *py,
+ const mp_int *qx, const mp_int *qy, mp_int *rx,
+ mp_int *ry, const ECGroup *group);
+
+/* Computes R = P - Q. Uses affine coordinates. */
+mp_err ec_GF2m_pt_sub_aff(const mp_int *px, const mp_int *py,
+ const mp_int *qx, const mp_int *qy, mp_int *rx,
+ mp_int *ry, const ECGroup *group);
+
+/* Computes R = 2P. Uses affine coordinates. */
+mp_err ec_GF2m_pt_dbl_aff(const mp_int *px, const mp_int *py, mp_int *rx,
+ mp_int *ry, const ECGroup *group);
+
+/* Validates a point on a GF2m curve. */
+mp_err ec_GF2m_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group);
+
+/* by default, this routine is unused and thus doesn't need to be compiled */
+#ifdef ECL_ENABLE_GF2M_PT_MUL_AFF
+/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
+ * a, b and p are the elliptic curve coefficients and the irreducible that
+ * determines the field GF2m. Uses affine coordinates. */
+mp_err ec_GF2m_pt_mul_aff(const mp_int *n, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *group);
+#endif
+
+/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
+ * a, b and p are the elliptic curve coefficients and the irreducible that
+ * determines the field GF2m. Uses Montgomery projective coordinates. */
+mp_err ec_GF2m_pt_mul_mont(const mp_int *n, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *group);
+
+#ifdef ECL_ENABLE_GF2M_PROJ
+/* Converts a point P(px, py) from affine coordinates to projective
+ * coordinates R(rx, ry, rz). */
+mp_err ec_GF2m_pt_aff2proj(const mp_int *px, const mp_int *py, mp_int *rx,
+ mp_int *ry, mp_int *rz, const ECGroup *group);
+
+/* Converts a point P(px, py, pz) from projective coordinates to affine
+ * coordinates R(rx, ry). */
+mp_err ec_GF2m_pt_proj2aff(const mp_int *px, const mp_int *py,
+ const mp_int *pz, mp_int *rx, mp_int *ry,
+ const ECGroup *group);
+
+/* Checks if point P(px, py, pz) is at infinity. Uses projective
+ * coordinates. */
+mp_err ec_GF2m_pt_is_inf_proj(const mp_int *px, const mp_int *py,
+ const mp_int *pz);
+
+/* Sets P(px, py, pz) to be the point at infinity. Uses projective
+ * coordinates. */
+mp_err ec_GF2m_pt_set_inf_proj(mp_int *px, mp_int *py, mp_int *pz);
+
+/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is
+ * (qx, qy, qz). Uses projective coordinates. */
+mp_err ec_GF2m_pt_add_proj(const mp_int *px, const mp_int *py,
+ const mp_int *pz, const mp_int *qx,
+ const mp_int *qy, mp_int *rx, mp_int *ry,
+ mp_int *rz, const ECGroup *group);
+
+/* Computes R = 2P. Uses projective coordinates. */
+mp_err ec_GF2m_pt_dbl_proj(const mp_int *px, const mp_int *py,
+ const mp_int *pz, mp_int *rx, mp_int *ry,
+ mp_int *rz, const ECGroup *group);
+
+/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
+ * a, b and p are the elliptic curve coefficients and the prime that
+ * determines the field GF2m. Uses projective coordinates. */
+mp_err ec_GF2m_pt_mul_proj(const mp_int *n, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *group);
+#endif
+
+#endif /* __ec2_h_ */
diff --git a/mozilla/security/nss/lib/freebl/ecl/ec2_163.c b/mozilla/security/nss/lib/freebl/ecl/ec2_163.c
new file mode 100644
index 0000000..6416321
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ec2_163.c
@@ -0,0 +1,259 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ec2.h"
+#include "mp_gf2m.h"
+#include "mp_gf2m-priv.h"
+#include "mpi.h"
+#include "mpi-priv.h"
+#include <stdlib.h>
+
+/* Fast reduction for polynomials over a 163-bit curve. Assumes reduction
+ * polynomial with terms {163, 7, 6, 3, 0}. */
+mp_err
+ec_GF2m_163_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit *u, z;
+
+ if (a != r) {
+ MP_CHECKOK(mp_copy(a, r));
+ }
+#ifdef ECL_SIXTY_FOUR_BIT
+ if (MP_USED(r) < 6) {
+ MP_CHECKOK(s_mp_pad(r, 6));
+ }
+ u = MP_DIGITS(r);
+ MP_USED(r) = 6;
+
+ /* u[5] only has 6 significant bits */
+ z = u[5];
+ u[2] ^= (z << 36) ^ (z << 35) ^ (z << 32) ^ (z << 29);
+ z = u[4];
+ u[2] ^= (z >> 28) ^ (z >> 29) ^ (z >> 32) ^ (z >> 35);
+ u[1] ^= (z << 36) ^ (z << 35) ^ (z << 32) ^ (z << 29);
+ z = u[3];
+ u[1] ^= (z >> 28) ^ (z >> 29) ^ (z >> 32) ^ (z >> 35);
+ u[0] ^= (z << 36) ^ (z << 35) ^ (z << 32) ^ (z << 29);
+ z = u[2] >> 35; /* z only has 29 significant bits */
+ u[0] ^= (z << 7) ^ (z << 6) ^ (z << 3) ^ z;
+ /* clear bits above 163 */
+ u[5] = u[4] = u[3] = 0;
+ u[2] ^= z << 35;
+#else
+ if (MP_USED(r) < 11) {
+ MP_CHECKOK(s_mp_pad(r, 11));
+ }
+ u = MP_DIGITS(r);
+ MP_USED(r) = 11;
+
+ /* u[11] only has 6 significant bits */
+ z = u[10];
+ u[5] ^= (z << 4) ^ (z << 3) ^ z ^ (z >> 3);
+ u[4] ^= (z << 29);
+ z = u[9];
+ u[5] ^= (z >> 28) ^ (z >> 29);
+ u[4] ^= (z << 4) ^ (z << 3) ^ z ^ (z >> 3);
+ u[3] ^= (z << 29);
+ z = u[8];
+ u[4] ^= (z >> 28) ^ (z >> 29);
+ u[3] ^= (z << 4) ^ (z << 3) ^ z ^ (z >> 3);
+ u[2] ^= (z << 29);
+ z = u[7];
+ u[3] ^= (z >> 28) ^ (z >> 29);
+ u[2] ^= (z << 4) ^ (z << 3) ^ z ^ (z >> 3);
+ u[1] ^= (z << 29);
+ z = u[6];
+ u[2] ^= (z >> 28) ^ (z >> 29);
+ u[1] ^= (z << 4) ^ (z << 3) ^ z ^ (z >> 3);
+ u[0] ^= (z << 29);
+ z = u[5] >> 3; /* z only has 29 significant bits */
+ u[1] ^= (z >> 25) ^ (z >> 26);
+ u[0] ^= (z << 7) ^ (z << 6) ^ (z << 3) ^ z;
+ /* clear bits above 163 */
+ u[11] = u[10] = u[9] = u[8] = u[7] = u[6] = 0;
+ u[5] ^= z << 3;
+#endif
+ s_mp_clamp(r);
+
+ CLEANUP:
+ return res;
+}
+
+/* Fast squaring for polynomials over a 163-bit curve. Assumes reduction
+ * polynomial with terms {163, 7, 6, 3, 0}. */
+mp_err
+ec_GF2m_163_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit *u, *v;
+
+ v = MP_DIGITS(a);
+
+#ifdef ECL_SIXTY_FOUR_BIT
+ if (MP_USED(a) < 3) {
+ return mp_bsqrmod(a, meth->irr_arr, r);
+ }
+ if (MP_USED(r) < 6) {
+ MP_CHECKOK(s_mp_pad(r, 6));
+ }
+ MP_USED(r) = 6;
+#else
+ if (MP_USED(a) < 6) {
+ return mp_bsqrmod(a, meth->irr_arr, r);
+ }
+ if (MP_USED(r) < 12) {
+ MP_CHECKOK(s_mp_pad(r, 12));
+ }
+ MP_USED(r) = 12;
+#endif
+ u = MP_DIGITS(r);
+
+#ifdef ECL_THIRTY_TWO_BIT
+ u[11] = gf2m_SQR1(v[5]);
+ u[10] = gf2m_SQR0(v[5]);
+ u[9] = gf2m_SQR1(v[4]);
+ u[8] = gf2m_SQR0(v[4]);
+ u[7] = gf2m_SQR1(v[3]);
+ u[6] = gf2m_SQR0(v[3]);
+#endif
+ u[5] = gf2m_SQR1(v[2]);
+ u[4] = gf2m_SQR0(v[2]);
+ u[3] = gf2m_SQR1(v[1]);
+ u[2] = gf2m_SQR0(v[1]);
+ u[1] = gf2m_SQR1(v[0]);
+ u[0] = gf2m_SQR0(v[0]);
+ return ec_GF2m_163_mod(r, r, meth);
+
+ CLEANUP:
+ return res;
+}
+
+/* Fast multiplication for polynomials over a 163-bit curve. Assumes
+ * reduction polynomial with terms {163, 7, 6, 3, 0}. */
+mp_err
+ec_GF2m_163_mul(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit a2 = 0, a1 = 0, a0, b2 = 0, b1 = 0, b0;
+
+#ifdef ECL_THIRTY_TWO_BIT
+ mp_digit a5 = 0, a4 = 0, a3 = 0, b5 = 0, b4 = 0, b3 = 0;
+ mp_digit rm[6];
+#endif
+
+ if (a == b) {
+ return ec_GF2m_163_sqr(a, r, meth);
+ } else {
+ switch (MP_USED(a)) {
+#ifdef ECL_THIRTY_TWO_BIT
+ case 6:
+ a5 = MP_DIGIT(a, 5);
+ case 5:
+ a4 = MP_DIGIT(a, 4);
+ case 4:
+ a3 = MP_DIGIT(a, 3);
+#endif
+ case 3:
+ a2 = MP_DIGIT(a, 2);
+ case 2:
+ a1 = MP_DIGIT(a, 1);
+ default:
+ a0 = MP_DIGIT(a, 0);
+ }
+ switch (MP_USED(b)) {
+#ifdef ECL_THIRTY_TWO_BIT
+ case 6:
+ b5 = MP_DIGIT(b, 5);
+ case 5:
+ b4 = MP_DIGIT(b, 4);
+ case 4:
+ b3 = MP_DIGIT(b, 3);
+#endif
+ case 3:
+ b2 = MP_DIGIT(b, 2);
+ case 2:
+ b1 = MP_DIGIT(b, 1);
+ default:
+ b0 = MP_DIGIT(b, 0);
+ }
+#ifdef ECL_SIXTY_FOUR_BIT
+ MP_CHECKOK(s_mp_pad(r, 6));
+ s_bmul_3x3(MP_DIGITS(r), a2, a1, a0, b2, b1, b0);
+ MP_USED(r) = 6;
+ s_mp_clamp(r);
+#else
+ MP_CHECKOK(s_mp_pad(r, 12));
+ s_bmul_3x3(MP_DIGITS(r) + 6, a5, a4, a3, b5, b4, b3);
+ s_bmul_3x3(MP_DIGITS(r), a2, a1, a0, b2, b1, b0);
+ s_bmul_3x3(rm, a5 ^ a2, a4 ^ a1, a3 ^ a0, b5 ^ b2, b4 ^ b1,
+ b3 ^ b0);
+ rm[5] ^= MP_DIGIT(r, 5) ^ MP_DIGIT(r, 11);
+ rm[4] ^= MP_DIGIT(r, 4) ^ MP_DIGIT(r, 10);
+ rm[3] ^= MP_DIGIT(r, 3) ^ MP_DIGIT(r, 9);
+ rm[2] ^= MP_DIGIT(r, 2) ^ MP_DIGIT(r, 8);
+ rm[1] ^= MP_DIGIT(r, 1) ^ MP_DIGIT(r, 7);
+ rm[0] ^= MP_DIGIT(r, 0) ^ MP_DIGIT(r, 6);
+ MP_DIGIT(r, 8) ^= rm[5];
+ MP_DIGIT(r, 7) ^= rm[4];
+ MP_DIGIT(r, 6) ^= rm[3];
+ MP_DIGIT(r, 5) ^= rm[2];
+ MP_DIGIT(r, 4) ^= rm[1];
+ MP_DIGIT(r, 3) ^= rm[0];
+ MP_USED(r) = 12;
+ s_mp_clamp(r);
+#endif
+ return ec_GF2m_163_mod(r, r, meth);
+ }
+
+ CLEANUP:
+ return res;
+}
+
+/* Wire in fast field arithmetic for 163-bit curves. */
+mp_err
+ec_group_set_gf2m163(ECGroup *group, ECCurveName name)
+{
+ group->meth->field_mod = &ec_GF2m_163_mod;
+ group->meth->field_mul = &ec_GF2m_163_mul;
+ group->meth->field_sqr = &ec_GF2m_163_sqr;
+ return MP_OKAY;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ec2_193.c b/mozilla/security/nss/lib/freebl/ecl/ec2_193.c
new file mode 100644
index 0000000..1a1e818
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ec2_193.c
@@ -0,0 +1,276 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ec2.h"
+#include "mp_gf2m.h"
+#include "mp_gf2m-priv.h"
+#include "mpi.h"
+#include "mpi-priv.h"
+#include <stdlib.h>
+
+/* Fast reduction for polynomials over a 193-bit curve. Assumes reduction
+ * polynomial with terms {193, 15, 0}. */
+mp_err
+ec_GF2m_193_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit *u, z;
+
+ if (a != r) {
+ MP_CHECKOK(mp_copy(a, r));
+ }
+#ifdef ECL_SIXTY_FOUR_BIT
+ if (MP_USED(r) < 7) {
+ MP_CHECKOK(s_mp_pad(r, 7));
+ }
+ u = MP_DIGITS(r);
+ MP_USED(r) = 7;
+
+ /* u[6] only has 2 significant bits */
+ z = u[6];
+ u[3] ^= (z << 14) ^ (z >> 1);
+ u[2] ^= (z << 63);
+ z = u[5];
+ u[3] ^= (z >> 50);
+ u[2] ^= (z << 14) ^ (z >> 1);
+ u[1] ^= (z << 63);
+ z = u[4];
+ u[2] ^= (z >> 50);
+ u[1] ^= (z << 14) ^ (z >> 1);
+ u[0] ^= (z << 63);
+ z = u[3] >> 1; /* z only has 63 significant bits */
+ u[1] ^= (z >> 49);
+ u[0] ^= (z << 15) ^ z;
+ /* clear bits above 193 */
+ u[6] = u[5] = u[4] = 0;
+ u[3] ^= z << 1;
+#else
+ if (MP_USED(r) < 13) {
+ MP_CHECKOK(s_mp_pad(r, 13));
+ }
+ u = MP_DIGITS(r);
+ MP_USED(r) = 13;
+
+ /* u[12] only has 2 significant bits */
+ z = u[12];
+ u[6] ^= (z << 14) ^ (z >> 1);
+ u[5] ^= (z << 31);
+ z = u[11];
+ u[6] ^= (z >> 18);
+ u[5] ^= (z << 14) ^ (z >> 1);
+ u[4] ^= (z << 31);
+ z = u[10];
+ u[5] ^= (z >> 18);
+ u[4] ^= (z << 14) ^ (z >> 1);
+ u[3] ^= (z << 31);
+ z = u[9];
+ u[4] ^= (z >> 18);
+ u[3] ^= (z << 14) ^ (z >> 1);
+ u[2] ^= (z << 31);
+ z = u[8];
+ u[3] ^= (z >> 18);
+ u[2] ^= (z << 14) ^ (z >> 1);
+ u[1] ^= (z << 31);
+ z = u[7];
+ u[2] ^= (z >> 18);
+ u[1] ^= (z << 14) ^ (z >> 1);
+ u[0] ^= (z << 31);
+ z = u[6] >> 1; /* z only has 31 significant bits */
+ u[1] ^= (z >> 17);
+ u[0] ^= (z << 15) ^ z;
+ /* clear bits above 193 */
+ u[12] = u[11] = u[10] = u[9] = u[8] = u[7] = 0;
+ u[6] ^= z << 1;
+#endif
+ s_mp_clamp(r);
+
+ CLEANUP:
+ return res;
+}
+
+/* Fast squaring for polynomials over a 193-bit curve. Assumes reduction
+ * polynomial with terms {193, 15, 0}. */
+mp_err
+ec_GF2m_193_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit *u, *v;
+
+ v = MP_DIGITS(a);
+
+#ifdef ECL_SIXTY_FOUR_BIT
+ if (MP_USED(a) < 4) {
+ return mp_bsqrmod(a, meth->irr_arr, r);
+ }
+ if (MP_USED(r) < 7) {
+ MP_CHECKOK(s_mp_pad(r, 7));
+ }
+ MP_USED(r) = 7;
+#else
+ if (MP_USED(a) < 7) {
+ return mp_bsqrmod(a, meth->irr_arr, r);
+ }
+ if (MP_USED(r) < 13) {
+ MP_CHECKOK(s_mp_pad(r, 13));
+ }
+ MP_USED(r) = 13;
+#endif
+ u = MP_DIGITS(r);
+
+#ifdef ECL_THIRTY_TWO_BIT
+ u[12] = gf2m_SQR0(v[6]);
+ u[11] = gf2m_SQR1(v[5]);
+ u[10] = gf2m_SQR0(v[5]);
+ u[9] = gf2m_SQR1(v[4]);
+ u[8] = gf2m_SQR0(v[4]);
+ u[7] = gf2m_SQR1(v[3]);
+#endif
+ u[6] = gf2m_SQR0(v[3]);
+ u[5] = gf2m_SQR1(v[2]);
+ u[4] = gf2m_SQR0(v[2]);
+ u[3] = gf2m_SQR1(v[1]);
+ u[2] = gf2m_SQR0(v[1]);
+ u[1] = gf2m_SQR1(v[0]);
+ u[0] = gf2m_SQR0(v[0]);
+ return ec_GF2m_193_mod(r, r, meth);
+
+ CLEANUP:
+ return res;
+}
+
+/* Fast multiplication for polynomials over a 193-bit curve. Assumes
+ * reduction polynomial with terms {193, 15, 0}. */
+mp_err
+ec_GF2m_193_mul(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit a3 = 0, a2 = 0, a1 = 0, a0, b3 = 0, b2 = 0, b1 = 0, b0;
+
+#ifdef ECL_THIRTY_TWO_BIT
+ mp_digit a6 = 0, a5 = 0, a4 = 0, b6 = 0, b5 = 0, b4 = 0;
+ mp_digit rm[8];
+#endif
+
+ if (a == b) {
+ return ec_GF2m_193_sqr(a, r, meth);
+ } else {
+ switch (MP_USED(a)) {
+#ifdef ECL_THIRTY_TWO_BIT
+ case 7:
+ a6 = MP_DIGIT(a, 6);
+ case 6:
+ a5 = MP_DIGIT(a, 5);
+ case 5:
+ a4 = MP_DIGIT(a, 4);
+#endif
+ case 4:
+ a3 = MP_DIGIT(a, 3);
+ case 3:
+ a2 = MP_DIGIT(a, 2);
+ case 2:
+ a1 = MP_DIGIT(a, 1);
+ default:
+ a0 = MP_DIGIT(a, 0);
+ }
+ switch (MP_USED(b)) {
+#ifdef ECL_THIRTY_TWO_BIT
+ case 7:
+ b6 = MP_DIGIT(b, 6);
+ case 6:
+ b5 = MP_DIGIT(b, 5);
+ case 5:
+ b4 = MP_DIGIT(b, 4);
+#endif
+ case 4:
+ b3 = MP_DIGIT(b, 3);
+ case 3:
+ b2 = MP_DIGIT(b, 2);
+ case 2:
+ b1 = MP_DIGIT(b, 1);
+ default:
+ b0 = MP_DIGIT(b, 0);
+ }
+#ifdef ECL_SIXTY_FOUR_BIT
+ MP_CHECKOK(s_mp_pad(r, 8));
+ s_bmul_4x4(MP_DIGITS(r), a3, a2, a1, a0, b3, b2, b1, b0);
+ MP_USED(r) = 8;
+ s_mp_clamp(r);
+#else
+ MP_CHECKOK(s_mp_pad(r, 14));
+ s_bmul_3x3(MP_DIGITS(r) + 8, a6, a5, a4, b6, b5, b4);
+ s_bmul_4x4(MP_DIGITS(r), a3, a2, a1, a0, b3, b2, b1, b0);
+ s_bmul_4x4(rm, a3, a6 ^ a2, a5 ^ a1, a4 ^ a0, b3, b6 ^ b2, b5 ^ b1,
+ b4 ^ b0);
+ rm[7] ^= MP_DIGIT(r, 7);
+ rm[6] ^= MP_DIGIT(r, 6);
+ rm[5] ^= MP_DIGIT(r, 5) ^ MP_DIGIT(r, 13);
+ rm[4] ^= MP_DIGIT(r, 4) ^ MP_DIGIT(r, 12);
+ rm[3] ^= MP_DIGIT(r, 3) ^ MP_DIGIT(r, 11);
+ rm[2] ^= MP_DIGIT(r, 2) ^ MP_DIGIT(r, 10);
+ rm[1] ^= MP_DIGIT(r, 1) ^ MP_DIGIT(r, 9);
+ rm[0] ^= MP_DIGIT(r, 0) ^ MP_DIGIT(r, 8);
+ MP_DIGIT(r, 11) ^= rm[7];
+ MP_DIGIT(r, 10) ^= rm[6];
+ MP_DIGIT(r, 9) ^= rm[5];
+ MP_DIGIT(r, 8) ^= rm[4];
+ MP_DIGIT(r, 7) ^= rm[3];
+ MP_DIGIT(r, 6) ^= rm[2];
+ MP_DIGIT(r, 5) ^= rm[1];
+ MP_DIGIT(r, 4) ^= rm[0];
+ MP_USED(r) = 14;
+ s_mp_clamp(r);
+#endif
+ return ec_GF2m_193_mod(r, r, meth);
+ }
+
+ CLEANUP:
+ return res;
+}
+
+/* Wire in fast field arithmetic for 193-bit curves. */
+mp_err
+ec_group_set_gf2m193(ECGroup *group, ECCurveName name)
+{
+ group->meth->field_mod = &ec_GF2m_193_mod;
+ group->meth->field_mul = &ec_GF2m_193_mul;
+ group->meth->field_sqr = &ec_GF2m_193_sqr;
+ return MP_OKAY;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ec2_233.c b/mozilla/security/nss/lib/freebl/ecl/ec2_233.c
new file mode 100644
index 0000000..3ecea93
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ec2_233.c
@@ -0,0 +1,299 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ec2.h"
+#include "mp_gf2m.h"
+#include "mp_gf2m-priv.h"
+#include "mpi.h"
+#include "mpi-priv.h"
+#include <stdlib.h>
+
+/* Fast reduction for polynomials over a 233-bit curve. Assumes reduction
+ * polynomial with terms {233, 74, 0}. */
+mp_err
+ec_GF2m_233_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit *u, z;
+
+ if (a != r) {
+ MP_CHECKOK(mp_copy(a, r));
+ }
+#ifdef ECL_SIXTY_FOUR_BIT
+ if (MP_USED(r) < 8) {
+ MP_CHECKOK(s_mp_pad(r, 8));
+ }
+ u = MP_DIGITS(r);
+ MP_USED(r) = 8;
+
+ /* u[7] only has 18 significant bits */
+ z = u[7];
+ u[4] ^= (z << 33) ^ (z >> 41);
+ u[3] ^= (z << 23);
+ z = u[6];
+ u[4] ^= (z >> 31);
+ u[3] ^= (z << 33) ^ (z >> 41);
+ u[2] ^= (z << 23);
+ z = u[5];
+ u[3] ^= (z >> 31);
+ u[2] ^= (z << 33) ^ (z >> 41);
+ u[1] ^= (z << 23);
+ z = u[4];
+ u[2] ^= (z >> 31);
+ u[1] ^= (z << 33) ^ (z >> 41);
+ u[0] ^= (z << 23);
+ z = u[3] >> 41; /* z only has 23 significant bits */
+ u[1] ^= (z << 10);
+ u[0] ^= z;
+ /* clear bits above 233 */
+ u[7] = u[6] = u[5] = u[4] = 0;
+ u[3] ^= z << 41;
+#else
+ if (MP_USED(r) < 15) {
+ MP_CHECKOK(s_mp_pad(r, 15));
+ }
+ u = MP_DIGITS(r);
+ MP_USED(r) = 15;
+
+ /* u[14] only has 18 significant bits */
+ z = u[14];
+ u[9] ^= (z << 1);
+ u[7] ^= (z >> 9);
+ u[6] ^= (z << 23);
+ z = u[13];
+ u[9] ^= (z >> 31);
+ u[8] ^= (z << 1);
+ u[6] ^= (z >> 9);
+ u[5] ^= (z << 23);
+ z = u[12];
+ u[8] ^= (z >> 31);
+ u[7] ^= (z << 1);
+ u[5] ^= (z >> 9);
+ u[4] ^= (z << 23);
+ z = u[11];
+ u[7] ^= (z >> 31);
+ u[6] ^= (z << 1);
+ u[4] ^= (z >> 9);
+ u[3] ^= (z << 23);
+ z = u[10];
+ u[6] ^= (z >> 31);
+ u[5] ^= (z << 1);
+ u[3] ^= (z >> 9);
+ u[2] ^= (z << 23);
+ z = u[9];
+ u[5] ^= (z >> 31);
+ u[4] ^= (z << 1);
+ u[2] ^= (z >> 9);
+ u[1] ^= (z << 23);
+ z = u[8];
+ u[4] ^= (z >> 31);
+ u[3] ^= (z << 1);
+ u[1] ^= (z >> 9);
+ u[0] ^= (z << 23);
+ z = u[7] >> 9; /* z only has 23 significant bits */
+ u[3] ^= (z >> 22);
+ u[2] ^= (z << 10);
+ u[0] ^= z;
+ /* clear bits above 233 */
+ u[14] = u[13] = u[12] = u[11] = u[10] = u[9] = u[8] = 0;
+ u[7] ^= z << 9;
+#endif
+ s_mp_clamp(r);
+
+ CLEANUP:
+ return res;
+}
+
+/* Fast squaring for polynomials over a 233-bit curve. Assumes reduction
+ * polynomial with terms {233, 74, 0}. */
+mp_err
+ec_GF2m_233_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit *u, *v;
+
+ v = MP_DIGITS(a);
+
+#ifdef ECL_SIXTY_FOUR_BIT
+ if (MP_USED(a) < 4) {
+ return mp_bsqrmod(a, meth->irr_arr, r);
+ }
+ if (MP_USED(r) < 8) {
+ MP_CHECKOK(s_mp_pad(r, 8));
+ }
+ MP_USED(r) = 8;
+#else
+ if (MP_USED(a) < 8) {
+ return mp_bsqrmod(a, meth->irr_arr, r);
+ }
+ if (MP_USED(r) < 15) {
+ MP_CHECKOK(s_mp_pad(r, 15));
+ }
+ MP_USED(r) = 15;
+#endif
+ u = MP_DIGITS(r);
+
+#ifdef ECL_THIRTY_TWO_BIT
+ u[14] = gf2m_SQR0(v[7]);
+ u[13] = gf2m_SQR1(v[6]);
+ u[12] = gf2m_SQR0(v[6]);
+ u[11] = gf2m_SQR1(v[5]);
+ u[10] = gf2m_SQR0(v[5]);
+ u[9] = gf2m_SQR1(v[4]);
+ u[8] = gf2m_SQR0(v[4]);
+#endif
+ u[7] = gf2m_SQR1(v[3]);
+ u[6] = gf2m_SQR0(v[3]);
+ u[5] = gf2m_SQR1(v[2]);
+ u[4] = gf2m_SQR0(v[2]);
+ u[3] = gf2m_SQR1(v[1]);
+ u[2] = gf2m_SQR0(v[1]);
+ u[1] = gf2m_SQR1(v[0]);
+ u[0] = gf2m_SQR0(v[0]);
+ return ec_GF2m_233_mod(r, r, meth);
+
+ CLEANUP:
+ return res;
+}
+
+/* Fast multiplication for polynomials over a 233-bit curve. Assumes
+ * reduction polynomial with terms {233, 74, 0}. */
+mp_err
+ec_GF2m_233_mul(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit a3 = 0, a2 = 0, a1 = 0, a0, b3 = 0, b2 = 0, b1 = 0, b0;
+
+#ifdef ECL_THIRTY_TWO_BIT
+ mp_digit a7 = 0, a6 = 0, a5 = 0, a4 = 0, b7 = 0, b6 = 0, b5 = 0, b4 =
+ 0;
+ mp_digit rm[8];
+#endif
+
+ if (a == b) {
+ return ec_GF2m_233_sqr(a, r, meth);
+ } else {
+ switch (MP_USED(a)) {
+#ifdef ECL_THIRTY_TWO_BIT
+ case 8:
+ a7 = MP_DIGIT(a, 7);
+ case 7:
+ a6 = MP_DIGIT(a, 6);
+ case 6:
+ a5 = MP_DIGIT(a, 5);
+ case 5:
+ a4 = MP_DIGIT(a, 4);
+#endif
+ case 4:
+ a3 = MP_DIGIT(a, 3);
+ case 3:
+ a2 = MP_DIGIT(a, 2);
+ case 2:
+ a1 = MP_DIGIT(a, 1);
+ default:
+ a0 = MP_DIGIT(a, 0);
+ }
+ switch (MP_USED(b)) {
+#ifdef ECL_THIRTY_TWO_BIT
+ case 8:
+ b7 = MP_DIGIT(b, 7);
+ case 7:
+ b6 = MP_DIGIT(b, 6);
+ case 6:
+ b5 = MP_DIGIT(b, 5);
+ case 5:
+ b4 = MP_DIGIT(b, 4);
+#endif
+ case 4:
+ b3 = MP_DIGIT(b, 3);
+ case 3:
+ b2 = MP_DIGIT(b, 2);
+ case 2:
+ b1 = MP_DIGIT(b, 1);
+ default:
+ b0 = MP_DIGIT(b, 0);
+ }
+#ifdef ECL_SIXTY_FOUR_BIT
+ MP_CHECKOK(s_mp_pad(r, 8));
+ s_bmul_4x4(MP_DIGITS(r), a3, a2, a1, a0, b3, b2, b1, b0);
+ MP_USED(r) = 8;
+ s_mp_clamp(r);
+#else
+ MP_CHECKOK(s_mp_pad(r, 16));
+ s_bmul_4x4(MP_DIGITS(r) + 8, a7, a6, a5, a4, b7, b6, b5, b4);
+ s_bmul_4x4(MP_DIGITS(r), a3, a2, a1, a0, b3, b2, b1, b0);
+ s_bmul_4x4(rm, a7 ^ a3, a6 ^ a2, a5 ^ a1, a4 ^ a0, b7 ^ b3,
+ b6 ^ b2, b5 ^ b1, b4 ^ b0);
+ rm[7] ^= MP_DIGIT(r, 7) ^ MP_DIGIT(r, 15);
+ rm[6] ^= MP_DIGIT(r, 6) ^ MP_DIGIT(r, 14);
+ rm[5] ^= MP_DIGIT(r, 5) ^ MP_DIGIT(r, 13);
+ rm[4] ^= MP_DIGIT(r, 4) ^ MP_DIGIT(r, 12);
+ rm[3] ^= MP_DIGIT(r, 3) ^ MP_DIGIT(r, 11);
+ rm[2] ^= MP_DIGIT(r, 2) ^ MP_DIGIT(r, 10);
+ rm[1] ^= MP_DIGIT(r, 1) ^ MP_DIGIT(r, 9);
+ rm[0] ^= MP_DIGIT(r, 0) ^ MP_DIGIT(r, 8);
+ MP_DIGIT(r, 11) ^= rm[7];
+ MP_DIGIT(r, 10) ^= rm[6];
+ MP_DIGIT(r, 9) ^= rm[5];
+ MP_DIGIT(r, 8) ^= rm[4];
+ MP_DIGIT(r, 7) ^= rm[3];
+ MP_DIGIT(r, 6) ^= rm[2];
+ MP_DIGIT(r, 5) ^= rm[1];
+ MP_DIGIT(r, 4) ^= rm[0];
+ MP_USED(r) = 16;
+ s_mp_clamp(r);
+#endif
+ return ec_GF2m_233_mod(r, r, meth);
+ }
+
+ CLEANUP:
+ return res;
+}
+
+/* Wire in fast field arithmetic for 233-bit curves. */
+mp_err
+ec_group_set_gf2m233(ECGroup *group, ECCurveName name)
+{
+ group->meth->field_mod = &ec_GF2m_233_mod;
+ group->meth->field_mul = &ec_GF2m_233_mul;
+ group->meth->field_sqr = &ec_GF2m_233_sqr;
+ return MP_OKAY;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ec2_aff.c b/mozilla/security/nss/lib/freebl/ecl/ec2_aff.c
new file mode 100644
index 0000000..64bb6fe
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ec2_aff.c
@@ -0,0 +1,346 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ec2.h"
+#include "mplogic.h"
+#include "mp_gf2m.h"
+#include <stdlib.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)
+{
+
+ 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));
+ MP_CHECKOK(mp_init(&tempx));
+ MP_CHECKOK(mp_init(&tempy));
+ /* 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));
+ /* 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));
+ MP_CHECKOK(mp_init(&accr));
+ MP_CHECKOK(mp_init(&tmp));
+ MP_CHECKOK(mp_init(&pxt));
+ MP_CHECKOK(mp_init(&pyt));
+
+ /* 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;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ec2_mont.c b/mozilla/security/nss/lib/freebl/ecl/ec2_mont.c
new file mode 100644
index 0000000..7167a98
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ec2_mont.c
@@ -0,0 +1,274 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ec2.h"
+#include "mplogic.h"
+#include "mp_gf2m.h"
+#include <stdlib.h>
+
+/* 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)
+{
+ mp_err res = MP_OKAY;
+ mp_int t1;
+
+ MP_DIGITS(&t1) = 0;
+ MP_CHECKOK(mp_init(&t1));
+
+ 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)
+{
+ mp_err res = MP_OKAY;
+ mp_int t1, t2;
+
+ MP_DIGITS(&t1) = 0;
+ MP_DIGITS(&t2) = 0;
+ MP_CHECKOK(mp_init(&t1));
+ MP_CHECKOK(mp_init(&t2));
+
+ 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));
+ MP_CHECKOK(mp_init(&t4));
+ MP_CHECKOK(mp_init(&t5));
+
+ 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));
+ MP_CHECKOK(mp_init(&x2));
+ MP_CHECKOK(mp_init(&z1));
+ MP_CHECKOK(mp_init(&z2));
+
+ /* 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));
+ MP_CHECKOK(gf2m_Mdouble(&x2, &z2, group));
+ } else {
+ MP_CHECKOK(gf2m_Madd(px, &x2, &z2, &x1, &z1, group));
+ MP_CHECKOK(gf2m_Mdouble(&x1, &z1, group));
+ }
+ mask >>= 1;
+ }
+ j = MP_DIGIT_BIT - 1;
+ mask = top_bit;
+ }
+
+ /* convert out of "projective" coordinates */
+ i = gf2m_Mxy(px, py, &x1, &z1, &x2, &z2, group);
+ if (i == 0) {
+ res = MP_BADARG;
+ goto CLEANUP;
+ } else if (i == 1) {
+ MP_CHECKOK(ec_GF2m_pt_set_inf_aff(rx, ry));
+ } else {
+ MP_CHECKOK(mp_copy(&x2, rx));
+ MP_CHECKOK(mp_copy(&z2, ry));
+ }
+
+ CLEANUP:
+ mp_clear(&x1);
+ mp_clear(&x2);
+ mp_clear(&z1);
+ mp_clear(&z2);
+ return res;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ec2_proj.c b/mozilla/security/nss/lib/freebl/ecl/ec2_proj.c
new file mode 100644
index 0000000..340e47d
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ec2_proj.c
@@ -0,0 +1,369 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ec2.h"
+#include "mplogic.h"
+#include "mp_gf2m.h"
+#include <stdlib.h>
+#ifdef ECL_DEBUG
+#include <assert.h>
+#endif
+
+/* by default, these routines are unused and thus don't need to be compiled */
+#ifdef ECL_ENABLE_GF2M_PROJ
+/* Converts a point P(px, py) from affine coordinates to 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_GF2m_pt_aff2proj(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;
+
+ 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 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_GF2m_pt_proj2aff(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;
+
+ MP_DIGITS(&z1) = 0;
+ MP_DIGITS(&z2) = 0;
+ MP_CHECKOK(mp_init(&z1));
+ MP_CHECKOK(mp_init(&z2));
+
+ /* if point at infinity, then set point at infinity and exit */
+ if (ec_GF2m_pt_is_inf_proj(px, py, pz) == MP_YES) {
+ MP_CHECKOK(ec_GF2m_pt_set_inf_aff(rx, ry));
+ goto CLEANUP;
+ }
+
+ /* transform (px, py, pz) into (px / pz, py / pz^2) */
+ 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(px, &z1, rx, group->meth));
+ MP_CHECKOK(group->meth->field_mul(py, &z2, ry, group->meth));
+ }
+
+ CLEANUP:
+ mp_clear(&z1);
+ mp_clear(&z2);
+ return res;
+}
+
+/* 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)
+{
+ return mp_cmp_z(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)
+{
+ 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 projective-affine coordinates. Assumes input is already
+ * field-encoded using field_enc, and returns output that is still
+ * field-encoded. Uses equation (3) from Hankerson, Hernandez, Menezes.
+ * Software Implementation of Elliptic Curve Cryptography Over Binary
+ * Fields. */
+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)
+{
+ mp_err res = MP_OKAY;
+ mp_int A, B, C, D, E, F, G;
+
+ /* If either P or Q is the point at infinity, then return the other
+ * point */
+ if (ec_GF2m_pt_is_inf_proj(px, py, pz) == MP_YES) {
+ return ec_GF2m_pt_aff2proj(qx, qy, rx, ry, rz, group);
+ }
+ if (ec_GF2m_pt_is_inf_aff(qx, qy) == MP_YES) {
+ MP_CHECKOK(mp_copy(px, rx));
+ MP_CHECKOK(mp_copy(py, ry));
+ return mp_copy(pz, rz);
+ }
+
+ MP_DIGITS(&A) = 0;
+ MP_DIGITS(&B) = 0;
+ MP_DIGITS(&C) = 0;
+ MP_DIGITS(&D) = 0;
+ MP_DIGITS(&E) = 0;
+ MP_DIGITS(&F) = 0;
+ MP_DIGITS(&G) = 0;
+ MP_CHECKOK(mp_init(&A));
+ MP_CHECKOK(mp_init(&B));
+ MP_CHECKOK(mp_init(&C));
+ MP_CHECKOK(mp_init(&D));
+ MP_CHECKOK(mp_init(&E));
+ MP_CHECKOK(mp_init(&F));
+ MP_CHECKOK(mp_init(&G));
+
+ /* D = pz^2 */
+ MP_CHECKOK(group->meth->field_sqr(pz, &D, group->meth));
+
+ /* A = qy * pz^2 + py */
+ MP_CHECKOK(group->meth->field_mul(qy, &D, &A, group->meth));
+ MP_CHECKOK(group->meth->field_add(&A, py, &A, group->meth));
+
+ /* B = qx * pz + px */
+ MP_CHECKOK(group->meth->field_mul(qx, pz, &B, group->meth));
+ MP_CHECKOK(group->meth->field_add(&B, px, &B, group->meth));
+
+ /* C = pz * B */
+ MP_CHECKOK(group->meth->field_mul(pz, &B, &C, group->meth));
+
+ /* D = B^2 * (C + a * pz^2) (using E as a temporary variable) */
+ MP_CHECKOK(group->meth->
+ field_mul(&group->curvea, &D, &D, group->meth));
+ MP_CHECKOK(group->meth->field_add(&C, &D, &D, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(&B, &E, group->meth));
+ MP_CHECKOK(group->meth->field_mul(&E, &D, &D, group->meth));
+
+ /* rz = C^2 */
+ MP_CHECKOK(group->meth->field_sqr(&C, rz, group->meth));
+
+ /* E = A * C */
+ MP_CHECKOK(group->meth->field_mul(&A, &C, &E, group->meth));
+
+ /* rx = A^2 + D + E */
+ MP_CHECKOK(group->meth->field_sqr(&A, rx, group->meth));
+ MP_CHECKOK(group->meth->field_add(rx, &D, rx, group->meth));
+ MP_CHECKOK(group->meth->field_add(rx, &E, rx, group->meth));
+
+ /* F = rx + qx * rz */
+ MP_CHECKOK(group->meth->field_mul(qx, rz, &F, group->meth));
+ MP_CHECKOK(group->meth->field_add(rx, &F, &F, group->meth));
+
+ /* G = rx + qy * rz */
+ MP_CHECKOK(group->meth->field_mul(qy, rz, &G, group->meth));
+ MP_CHECKOK(group->meth->field_add(rx, &G, &G, group->meth));
+
+ /* ry = E * F + rz * G (using G as a temporary variable) */
+ MP_CHECKOK(group->meth->field_mul(rz, &G, &G, group->meth));
+ MP_CHECKOK(group->meth->field_mul(&E, &F, ry, group->meth));
+ MP_CHECKOK(group->meth->field_add(ry, &G, ry, group->meth));
+
+ CLEANUP:
+ mp_clear(&A);
+ mp_clear(&B);
+ mp_clear(&C);
+ mp_clear(&D);
+ mp_clear(&E);
+ mp_clear(&F);
+ mp_clear(&G);
+ return res;
+}
+
+/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses
+ * projective coordinates.
+ *
+ * Assumes input is already field-encoded using field_enc, and returns
+ * output that is still field-encoded.
+ *
+ * Uses equation (3) from Hankerson, Hernandez, Menezes. Software
+ * Implementation of Elliptic Curve Cryptography Over Binary Fields.
+ */
+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)
+{
+ mp_err res = MP_OKAY;
+ mp_int t0, t1;
+
+ if (ec_GF2m_pt_is_inf_proj(px, py, pz) == MP_YES) {
+ return ec_GF2m_pt_set_inf_proj(rx, ry, rz);
+ }
+
+ MP_DIGITS(&t0) = 0;
+ MP_DIGITS(&t1) = 0;
+ MP_CHECKOK(mp_init(&t0));
+ MP_CHECKOK(mp_init(&t1));
+
+ /* t0 = px^2 */
+ /* t1 = pz^2 */
+ MP_CHECKOK(group->meth->field_sqr(px, &t0, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(pz, &t1, group->meth));
+
+ /* rz = px^2 * pz^2 */
+ MP_CHECKOK(group->meth->field_mul(&t0, &t1, rz, group->meth));
+
+ /* t0 = px^4 */
+ /* t1 = b * pz^4 */
+ MP_CHECKOK(group->meth->field_sqr(&t0, &t0, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(&t1, &t1, group->meth));
+ MP_CHECKOK(group->meth->
+ field_mul(&group->curveb, &t1, &t1, group->meth));
+
+ /* rx = px^4 + b * pz^4 */
+ MP_CHECKOK(group->meth->field_add(&t0, &t1, rx, group->meth));
+
+ /* ry = b * pz^4 * rz + rx * (a * rz + py^2 + b * pz^4) */
+ MP_CHECKOK(group->meth->field_sqr(py, ry, group->meth));
+ MP_CHECKOK(group->meth->field_add(ry, &t1, ry, group->meth));
+ /* t0 = a * rz */
+ MP_CHECKOK(group->meth->
+ field_mul(&group->curvea, rz, &t0, group->meth));
+ MP_CHECKOK(group->meth->field_add(&t0, ry, ry, group->meth));
+ MP_CHECKOK(group->meth->field_mul(rx, ry, ry, group->meth));
+ /* t1 = b * pz^4 * rz */
+ MP_CHECKOK(group->meth->field_mul(&t1, rz, &t1, group->meth));
+ MP_CHECKOK(group->meth->field_add(&t1, ry, ry, group->meth));
+
+ CLEANUP:
+ mp_clear(&t0);
+ mp_clear(&t1);
+ return res;
+}
+
+/* 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. Elliptic curve points P and R can be
+ * identical. Uses mixed projective-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_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)
+{
+ mp_err res = MP_OKAY;
+ mp_int precomp[16][2], rz;
+ mp_digit precomp_arr[ECL_MAX_FIELD_SIZE_DIGITS * 16 * 2], *t;
+ int i, ni, d;
+
+ ARGCHK(group != NULL, MP_BADARG);
+ ARGCHK((n != NULL) && (px != NULL) && (py != NULL), MP_BADARG);
+
+ /* initialize precomputation table */
+ t = precomp_arr;
+ for (i = 0; i < 16; i++) {
+ /* x co-ord */
+ MP_SIGN(&precomp[i][0]) = MP_ZPOS;
+ MP_ALLOC(&precomp[i][0]) = ECL_MAX_FIELD_SIZE_DIGITS;
+ MP_USED(&precomp[i][0]) = 1;
+ *t = 0;
+ MP_DIGITS(&precomp[i][0]) = t;
+ t += ECL_MAX_FIELD_SIZE_DIGITS;
+ /* y co-ord */
+ MP_SIGN(&precomp[i][1]) = MP_ZPOS;
+ MP_ALLOC(&precomp[i][1]) = ECL_MAX_FIELD_SIZE_DIGITS;
+ MP_USED(&precomp[i][1]) = 1;
+ *t = 0;
+ MP_DIGITS(&precomp[i][1]) = t;
+ t += ECL_MAX_FIELD_SIZE_DIGITS;
+ }
+
+ /* 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_DIGITS(&rz) = 0;
+ MP_CHECKOK(mp_init(&rz));
+ MP_CHECKOK(ec_GF2m_pt_set_inf_proj(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_GF2m_pt_dbl_proj(rx, ry, &rz, rx, ry, &rz, group));
+ MP_CHECKOK(ec_GF2m_pt_dbl_proj(rx, ry, &rz, rx, ry, &rz, group));
+ MP_CHECKOK(ec_GF2m_pt_dbl_proj(rx, ry, &rz, rx, ry, &rz, group));
+ MP_CHECKOK(ec_GF2m_pt_dbl_proj(rx, ry, &rz, rx, ry, &rz, group));
+ /* R = R + (ni * P) */
+ MP_CHECKOK(ec_GF2m_pt_add_proj
+ (rx, ry, &rz, &precomp[ni][0], &precomp[ni][1], rx, ry,
+ &rz, group));
+ }
+
+ /* convert result S to affine coordinates */
+ MP_CHECKOK(ec_GF2m_pt_proj2aff(rx, ry, &rz, rx, ry, group));
+
+ CLEANUP:
+ mp_clear(&rz);
+ return res;
+}
+#endif
diff --git a/mozilla/security/nss/lib/freebl/ecl/ec_naf.c b/mozilla/security/nss/lib/freebl/ecl/ec_naf.c
new file mode 100644
index 0000000..9ef3a55
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ec_naf.c
@@ -0,0 +1,103 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ecl-priv.h"
+
+/* Returns 2^e as an integer. This is meant to be used for small powers of
+ * two. */
+int
+ec_twoTo(int e)
+{
+ int a = 1;
+ int i;
+
+ for (i = 0; i < e; i++) {
+ a *= 2;
+ }
+ return a;
+}
+
+/* Computes the windowed non-adjacent-form (NAF) of a scalar. Out should
+ * be an array of signed char's to output to, bitsize should be the number
+ * of bits of out, in is the original scalar, and w is the window size.
+ * NAF is discussed in the paper: D. Hankerson, J. Hernandez and A.
+ * Menezes, "Software implementation of elliptic curve cryptography over
+ * binary fields", Proc. CHES 2000. */
+mp_err
+ec_compute_wNAF(signed char *out, int bitsize, const mp_int *in, int w)
+{
+ mp_int k;
+ mp_err res = MP_OKAY;
+ int i, twowm1, mask;
+
+ twowm1 = ec_twoTo(w - 1);
+ mask = 2 * twowm1 - 1;
+
+ MP_DIGITS(&k) = 0;
+ MP_CHECKOK(mp_init_copy(&k, in));
+
+ i = 0;
+ /* Compute wNAF form */
+ while (mp_cmp_z(&k) > 0) {
+ if (mp_isodd(&k)) {
+ out[i] = MP_DIGIT(&k, 0) & mask;
+ if (out[i] >= twowm1)
+ out[i] -= 2 * twowm1;
+
+ /* Subtract off out[i]. Note mp_sub_d only works with
+ * unsigned digits */
+ if (out[i] >= 0) {
+ mp_sub_d(&k, out[i], &k);
+ } else {
+ mp_add_d(&k, -(out[i]), &k);
+ }
+ } else {
+ out[i] = 0;
+ }
+ mp_div_2(&k, &k);
+ i++;
+ }
+ /* Zero out the remaining elements of the out array. */
+ for (; i < bitsize + 1; i++) {
+ out[i] = 0;
+ }
+ CLEANUP:
+ mp_clear(&k);
+ return res;
+
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecl-curve.h b/mozilla/security/nss/lib/freebl/ecl/ecl-curve.h
new file mode 100644
index 0000000..3a01dc8
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecl-curve.h
@@ -0,0 +1,144 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ecl-exp.h"
+#include <stdlib.h>
+
+#ifndef __ecl_curve_h_
+#define __ecl_curve_h_
+
+#ifdef NSS_ECC_MORE_THAN_SUITE_B
+#error This source file is for Basic ECC only .
+#endif
+
+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
+};
+
+/* mapping between ECCurveName enum and pointers to ECCurveParams */
+static const ECCurveParams *ecCurve_map[] = {
+ NULL, /* ECCurve_noName */
+ NULL, /* ECCurve_NIST_P192 */
+ NULL, /* ECCurve_NIST_P224 */
+ &ecCurve_NIST_P256, /* ECCurve_NIST_P256 */
+ &ecCurve_NIST_P384, /* ECCurve_NIST_P384 */
+ &ecCurve_NIST_P521, /* ECCurve_NIST_P521 */
+ NULL, /* ECCurve_NIST_K163 */
+ NULL, /* ECCurve_NIST_B163 */
+ NULL, /* ECCurve_NIST_K233 */
+ NULL, /* ECCurve_NIST_B233 */
+ NULL, /* ECCurve_NIST_K283 */
+ NULL, /* ECCurve_NIST_B283 */
+ NULL, /* ECCurve_NIST_K409 */
+ NULL, /* ECCurve_NIST_B409 */
+ NULL, /* ECCurve_NIST_K571 */
+ NULL, /* ECCurve_NIST_B571 */
+ NULL, /* ECCurve_X9_62_PRIME_192V2 */
+ NULL, /* ECCurve_X9_62_PRIME_192V3 */
+ NULL, /* ECCurve_X9_62_PRIME_239V1 */
+ NULL, /* ECCurve_X9_62_PRIME_239V2 */
+ NULL, /* ECCurve_X9_62_PRIME_239V3 */
+ NULL, /* ECCurve_X9_62_CHAR2_PNB163V1 */
+ NULL, /* ECCurve_X9_62_CHAR2_PNB163V2 */
+ NULL, /* ECCurve_X9_62_CHAR2_PNB163V3 */
+ NULL, /* ECCurve_X9_62_CHAR2_PNB176V1 */
+ NULL, /* ECCurve_X9_62_CHAR2_TNB191V1 */
+ NULL, /* ECCurve_X9_62_CHAR2_TNB191V2 */
+ NULL, /* ECCurve_X9_62_CHAR2_TNB191V3 */
+ NULL, /* ECCurve_X9_62_CHAR2_PNB208W1 */
+ NULL, /* ECCurve_X9_62_CHAR2_TNB239V1 */
+ NULL, /* ECCurve_X9_62_CHAR2_TNB239V2 */
+ NULL, /* ECCurve_X9_62_CHAR2_TNB239V3 */
+ NULL, /* ECCurve_X9_62_CHAR2_PNB272W1 */
+ NULL, /* ECCurve_X9_62_CHAR2_PNB304W1 */
+ NULL, /* ECCurve_X9_62_CHAR2_TNB359V1 */
+ NULL, /* ECCurve_X9_62_CHAR2_PNB368W1 */
+ NULL, /* ECCurve_X9_62_CHAR2_TNB431R1 */
+ NULL, /* ECCurve_SECG_PRIME_112R1 */
+ NULL, /* ECCurve_SECG_PRIME_112R2 */
+ NULL, /* ECCurve_SECG_PRIME_128R1 */
+ NULL, /* ECCurve_SECG_PRIME_128R2 */
+ NULL, /* ECCurve_SECG_PRIME_160K1 */
+ NULL, /* ECCurve_SECG_PRIME_160R1 */
+ NULL, /* ECCurve_SECG_PRIME_160R2 */
+ NULL, /* ECCurve_SECG_PRIME_192K1 */
+ NULL, /* ECCurve_SECG_PRIME_224K1 */
+ NULL, /* ECCurve_SECG_PRIME_256K1 */
+ NULL, /* ECCurve_SECG_CHAR2_113R1 */
+ NULL, /* ECCurve_SECG_CHAR2_113R2 */
+ NULL, /* ECCurve_SECG_CHAR2_131R1 */
+ NULL, /* ECCurve_SECG_CHAR2_131R2 */
+ NULL, /* ECCurve_SECG_CHAR2_163R1 */
+ NULL, /* ECCurve_SECG_CHAR2_193R1 */
+ NULL, /* ECCurve_SECG_CHAR2_193R2 */
+ NULL, /* ECCurve_SECG_CHAR2_239K1 */
+ NULL, /* ECCurve_WTLS_1 */
+ NULL, /* ECCurve_WTLS_8 */
+ NULL, /* ECCurve_WTLS_9 */
+ NULL /* ECCurve_pastLastCurve */
+};
+
+#endif
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecl-exp.h b/mozilla/security/nss/lib/freebl/ecl/ecl-exp.h
new file mode 100644
index 0000000..77f3ebb
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecl-exp.h
@@ -0,0 +1,196 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __ecl_exp_h_
+#define __ecl_exp_h_
+
+/* Curve field type */
+typedef enum {
+ ECField_GFp,
+ ECField_GF2m
+} ECField;
+
+/* Hexadecimal encoding of curve parameters */
+struct ECCurveParamsStr {
+ char *text;
+ ECField field;
+ unsigned int size;
+ char *irr;
+ char *curvea;
+ char *curveb;
+ char *genx;
+ char *geny;
+ char *order;
+ int cofactor;
+};
+typedef struct ECCurveParamsStr ECCurveParams;
+
+/* Named curve parameters */
+typedef enum {
+
+ ECCurve_noName = 0,
+
+ /* NIST prime curves */
+ ECCurve_NIST_P192,
+ ECCurve_NIST_P224,
+ ECCurve_NIST_P256,
+ ECCurve_NIST_P384,
+ ECCurve_NIST_P521,
+
+ /* NIST binary curves */
+ ECCurve_NIST_K163,
+ ECCurve_NIST_B163,
+ ECCurve_NIST_K233,
+ ECCurve_NIST_B233,
+ ECCurve_NIST_K283,
+ ECCurve_NIST_B283,
+ ECCurve_NIST_K409,
+ ECCurve_NIST_B409,
+ ECCurve_NIST_K571,
+ ECCurve_NIST_B571,
+
+ /* ANSI X9.62 prime curves */
+ /* ECCurve_X9_62_PRIME_192V1 == ECCurve_NIST_P192 */
+ ECCurve_X9_62_PRIME_192V2,
+ ECCurve_X9_62_PRIME_192V3,
+ ECCurve_X9_62_PRIME_239V1,
+ ECCurve_X9_62_PRIME_239V2,
+ ECCurve_X9_62_PRIME_239V3,
+ /* ECCurve_X9_62_PRIME_256V1 == ECCurve_NIST_P256 */
+
+ /* ANSI X9.62 binary curves */
+ ECCurve_X9_62_CHAR2_PNB163V1,
+ ECCurve_X9_62_CHAR2_PNB163V2,
+ ECCurve_X9_62_CHAR2_PNB163V3,
+ ECCurve_X9_62_CHAR2_PNB176V1,
+ ECCurve_X9_62_CHAR2_TNB191V1,
+ ECCurve_X9_62_CHAR2_TNB191V2,
+ ECCurve_X9_62_CHAR2_TNB191V3,
+ ECCurve_X9_62_CHAR2_PNB208W1,
+ ECCurve_X9_62_CHAR2_TNB239V1,
+ ECCurve_X9_62_CHAR2_TNB239V2,
+ ECCurve_X9_62_CHAR2_TNB239V3,
+ ECCurve_X9_62_CHAR2_PNB272W1,
+ ECCurve_X9_62_CHAR2_PNB304W1,
+ ECCurve_X9_62_CHAR2_TNB359V1,
+ ECCurve_X9_62_CHAR2_PNB368W1,
+ ECCurve_X9_62_CHAR2_TNB431R1,
+
+ /* SEC2 prime curves */
+ ECCurve_SECG_PRIME_112R1,
+ ECCurve_SECG_PRIME_112R2,
+ ECCurve_SECG_PRIME_128R1,
+ ECCurve_SECG_PRIME_128R2,
+ ECCurve_SECG_PRIME_160K1,
+ ECCurve_SECG_PRIME_160R1,
+ ECCurve_SECG_PRIME_160R2,
+ ECCurve_SECG_PRIME_192K1,
+ /* ECCurve_SECG_PRIME_192R1 == ECCurve_NIST_P192 */
+ ECCurve_SECG_PRIME_224K1,
+ /* ECCurve_SECG_PRIME_224R1 == ECCurve_NIST_P224 */
+ ECCurve_SECG_PRIME_256K1,
+ /* ECCurve_SECG_PRIME_256R1 == ECCurve_NIST_P256 */
+ /* ECCurve_SECG_PRIME_384R1 == ECCurve_NIST_P384 */
+ /* ECCurve_SECG_PRIME_521R1 == ECCurve_NIST_P521 */
+
+ /* SEC2 binary curves */
+ ECCurve_SECG_CHAR2_113R1,
+ ECCurve_SECG_CHAR2_113R2,
+ ECCurve_SECG_CHAR2_131R1,
+ ECCurve_SECG_CHAR2_131R2,
+ /* ECCurve_SECG_CHAR2_163K1 == ECCurve_NIST_K163 */
+ ECCurve_SECG_CHAR2_163R1,
+ /* ECCurve_SECG_CHAR2_163R2 == ECCurve_NIST_B163 */
+ ECCurve_SECG_CHAR2_193R1,
+ ECCurve_SECG_CHAR2_193R2,
+ /* ECCurve_SECG_CHAR2_233K1 == ECCurve_NIST_K233 */
+ /* ECCurve_SECG_CHAR2_233R1 == ECCurve_NIST_B233 */
+ ECCurve_SECG_CHAR2_239K1,
+ /* ECCurve_SECG_CHAR2_283K1 == ECCurve_NIST_K283 */
+ /* ECCurve_SECG_CHAR2_283R1 == ECCurve_NIST_B283 */
+ /* ECCurve_SECG_CHAR2_409K1 == ECCurve_NIST_K409 */
+ /* ECCurve_SECG_CHAR2_409R1 == ECCurve_NIST_B409 */
+ /* ECCurve_SECG_CHAR2_571K1 == ECCurve_NIST_K571 */
+ /* ECCurve_SECG_CHAR2_571R1 == ECCurve_NIST_B571 */
+
+ /* WTLS curves */
+ ECCurve_WTLS_1,
+ /* there is no WTLS 2 curve */
+ /* ECCurve_WTLS_3 == ECCurve_NIST_K163 */
+ /* ECCurve_WTLS_4 == ECCurve_SECG_CHAR2_113R1 */
+ /* ECCurve_WTLS_5 == ECCurve_X9_62_CHAR2_PNB163V1 */
+ /* ECCurve_WTLS_6 == ECCurve_SECG_PRIME_112R1 */
+ /* ECCurve_WTLS_7 == ECCurve_SECG_PRIME_160R1 */
+ ECCurve_WTLS_8,
+ ECCurve_WTLS_9,
+ /* ECCurve_WTLS_10 == ECCurve_NIST_K233 */
+ /* ECCurve_WTLS_11 == ECCurve_NIST_B233 */
+ /* ECCurve_WTLS_12 == ECCurve_NIST_P224 */
+
+ ECCurve_pastLastCurve
+} ECCurveName;
+
+/* Aliased named curves */
+
+#define ECCurve_X9_62_PRIME_192V1 ECCurve_NIST_P192
+#define ECCurve_X9_62_PRIME_256V1 ECCurve_NIST_P256
+#define ECCurve_SECG_PRIME_192R1 ECCurve_NIST_P192
+#define ECCurve_SECG_PRIME_224R1 ECCurve_NIST_P224
+#define ECCurve_SECG_PRIME_256R1 ECCurve_NIST_P256
+#define ECCurve_SECG_PRIME_384R1 ECCurve_NIST_P384
+#define ECCurve_SECG_PRIME_521R1 ECCurve_NIST_P521
+#define ECCurve_SECG_CHAR2_163K1 ECCurve_NIST_K163
+#define ECCurve_SECG_CHAR2_163R2 ECCurve_NIST_B163
+#define ECCurve_SECG_CHAR2_233K1 ECCurve_NIST_K233
+#define ECCurve_SECG_CHAR2_233R1 ECCurve_NIST_B233
+#define ECCurve_SECG_CHAR2_283K1 ECCurve_NIST_K283
+#define ECCurve_SECG_CHAR2_283R1 ECCurve_NIST_B283
+#define ECCurve_SECG_CHAR2_409K1 ECCurve_NIST_K409
+#define ECCurve_SECG_CHAR2_409R1 ECCurve_NIST_B409
+#define ECCurve_SECG_CHAR2_571K1 ECCurve_NIST_K571
+#define ECCurve_SECG_CHAR2_571R1 ECCurve_NIST_B571
+#define ECCurve_WTLS_3 ECCurve_NIST_K163
+#define ECCurve_WTLS_4 ECCurve_SECG_CHAR2_113R1
+#define ECCurve_WTLS_5 ECCurve_X9_62_CHAR2_PNB163V1
+#define ECCurve_WTLS_6 ECCurve_SECG_PRIME_112R1
+#define ECCurve_WTLS_7 ECCurve_SECG_PRIME_160R1
+#define ECCurve_WTLS_10 ECCurve_NIST_K233
+#define ECCurve_WTLS_11 ECCurve_NIST_B233
+#define ECCurve_WTLS_12 ECCurve_NIST_P224
+
+#endif /* __ecl_exp_h_ */
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecl-priv.h b/mozilla/security/nss/lib/freebl/ecl/ecl-priv.h
new file mode 100644
index 0000000..05abb4d
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecl-priv.h
@@ -0,0 +1,281 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __ecl_priv_h_
+#define __ecl_priv_h_
+
+#include "ecl.h"
+#include "mpi.h"
+#include "mplogic.h"
+
+/* MAX_FIELD_SIZE_DIGITS is the maximum size of field element supported */
+/* the following needs to go away... */
+#if defined(MP_USE_LONG_LONG_DIGIT) || defined(MP_USE_LONG_DIGIT)
+#define ECL_SIXTY_FOUR_BIT
+#else
+#define ECL_THIRTY_TWO_BIT
+#endif
+
+#define ECL_CURVE_DIGITS(curve_size_in_bits) \
+ (((curve_size_in_bits)+(sizeof(mp_digit)*8-1))/(sizeof(mp_digit)*8))
+#define ECL_BITS (sizeof(mp_digit)*8)
+#define ECL_MAX_FIELD_SIZE_DIGITS (80/sizeof(mp_digit))
+
+/* Gets the i'th bit in the binary representation of a. If i >= length(a),
+ * then return 0. (The above behaviour differs from mpl_get_bit, which
+ * causes an error if i >= length(a).) */
+#define MP_GET_BIT(a, i) \
+ ((i) >= mpl_significant_bits((a))) ? 0 : mpl_get_bit((a), (i))
+
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+#define MP_ADD_CARRY(a1, a2, s, cin, cout) \
+ { mp_word w; \
+ w = ((mp_word)(cin)) + (a1) + (a2); \
+ s = ACCUM(w); \
+ cout = CARRYOUT(w); }
+
+#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;
+ /* 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_ */
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecl.c b/mozilla/security/nss/lib/freebl/ecl/ecl.c
new file mode 100644
index 0000000..84080df
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecl.c
@@ -0,0 +1,429 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "mpi.h"
+#include "mplogic.h"
+#include "ecl.h"
+#include "ecl-priv.h"
+#include "ec2.h"
+#include "ecp.h"
+#include <stdlib.h>
+#include <string.h>
+
+/* Allocate memory for a new ECGroup object. */
+ECGroup *
+ECGroup_new()
+{
+ mp_err res = MP_OKAY;
+ ECGroup *group;
+ group = (ECGroup *) malloc(sizeof(ECGroup));
+ 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));
+ MP_CHECKOK(mp_init(&group->curveb));
+ MP_CHECKOK(mp_init(&group->genx));
+ MP_CHECKOK(mp_init(&group->geny));
+ MP_CHECKOK(mp_init(&group->order));
+
+ 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();
+ 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();
+ 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();
+ 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)
+{
+ 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));
+ MP_CHECKOK(mp_init(&curvea));
+ MP_CHECKOK(mp_init(&curveb));
+ MP_CHECKOK(mp_init(&genx));
+ MP_CHECKOK(mp_init(&geny));
+ MP_CHECKOK(mp_init(&order));
+ 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)) {
+ group->text = strdup(params->text);
+ if (group->text == NULL) {
+ res = MP_MEM;
+ }
+ }
+
+ 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)
+{
+ return ecgroup_fromNameAndHex(ECCurve_noName, params);
+}
+
+/* Construct ECGroup from named parameters. */
+ECGroup *
+ECGroup_fromName(const ECCurveName name)
+{
+ ECGroup *group = NULL;
+ ECCurveParams *params = NULL;
+ mp_err res = MP_OKAY;
+
+ params = EC_GetNamedCurveParams(name);
+ if (params == NULL) {
+ res = MP_UNDEF;
+ goto CLEANUP;
+ }
+
+ /* construct actual group */
+ group = ecgroup_fromNameAndHex(name, params);
+ 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)
+ free(group->text);
+ if (group->extra_free != NULL)
+ group->extra_free(group);
+ free(group);
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecl.h b/mozilla/security/nss/lib/freebl/ecl/ecl.h
new file mode 100644
index 0000000..dbd86c2
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecl.h
@@ -0,0 +1,91 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* Although this is not an exported header file, code which uses elliptic
+ * curve point operations will need to include it. */
+
+#ifndef __ecl_h_
+#define __ecl_h_
+
+#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);
+
+/* Construct ECGroup from named parameters. */
+ECGroup *ECGroup_fromName(const ECCurveName name);
+
+/* Free an allocated ECGroup. */
+void ECGroup_free(ECGroup *group);
+
+/* Construct ECCurveParams from an ECCurveName */
+ECCurveParams *EC_GetNamedCurveParams(const ECCurveName name);
+
+/* Duplicates an ECCurveParams */
+ECCurveParams *ECCurveParams_dup(const ECCurveParams * params);
+
+/* 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_ */
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecl_curve.c b/mozilla/security/nss/lib/freebl/ecl/ecl_curve.c
new file mode 100644
index 0000000..a0a7bd3
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecl_curve.c
@@ -0,0 +1,123 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ecl.h"
+#include "ecl-curve.h"
+#include "ecl-priv.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK(func) if ((func) == NULL) { res = 0; goto CLEANUP; }
+
+/* Duplicates an ECCurveParams */
+ECCurveParams *
+ECCurveParams_dup(const ECCurveParams * params)
+{
+ int res = 1;
+ ECCurveParams *ret = NULL;
+
+ CHECK(ret = (ECCurveParams *) calloc(1, sizeof(ECCurveParams)));
+ if (params->text != NULL) {
+ CHECK(ret->text = strdup(params->text));
+ }
+ ret->field = params->field;
+ ret->size = params->size;
+ if (params->irr != NULL) {
+ CHECK(ret->irr = strdup(params->irr));
+ }
+ if (params->curvea != NULL) {
+ CHECK(ret->curvea = strdup(params->curvea));
+ }
+ if (params->curveb != NULL) {
+ CHECK(ret->curveb = strdup(params->curveb));
+ }
+ if (params->genx != NULL) {
+ CHECK(ret->genx = strdup(params->genx));
+ }
+ if (params->geny != NULL) {
+ CHECK(ret->geny = strdup(params->geny));
+ }
+ if (params->order != NULL) {
+ CHECK(ret->order = strdup(params->order));
+ }
+ 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)
+{
+ if ((name <= ECCurve_noName) || (ECCurve_pastLastCurve <= name) ||
+ (ecCurve_map[name] == NULL)) {
+ return NULL;
+ } else {
+ return ECCurveParams_dup(ecCurve_map[name]);
+ }
+}
+
+/* Free the memory allocated (if any) to an ECCurveParams object. */
+void
+EC_FreeCurveParams(ECCurveParams * params)
+{
+ if (params == NULL)
+ return;
+ if (params->text != NULL)
+ free(params->text);
+ if (params->irr != NULL)
+ free(params->irr);
+ if (params->curvea != NULL)
+ free(params->curvea);
+ if (params->curveb != NULL)
+ free(params->curveb);
+ if (params->genx != NULL)
+ free(params->genx);
+ if (params->geny != NULL)
+ free(params->geny);
+ if (params->order != NULL)
+ free(params->order);
+ free(params);
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecl_gf.c b/mozilla/security/nss/lib/freebl/ecl/ecl_gf.c
new file mode 100644
index 0000000..08fa0c3
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecl_gf.c
@@ -0,0 +1,1032 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "mpi.h"
+#include "mp_gf2m.h"
+#include "ecl-priv.h"
+#include "mpi-priv.h"
+#include <stdlib.h>
+
+/* Allocate memory for a new GFMethod object. */
+GFMethod *
+GFMethod_new()
+{
+ mp_err res = MP_OKAY;
+ GFMethod *meth;
+ meth = (GFMethod *) malloc(sizeof(GFMethod));
+ if (meth == NULL)
+ return NULL;
+ meth->constructed = MP_YES;
+ MP_DIGITS(&meth->irr) = 0;
+ meth->extra_free = NULL;
+ MP_CHECKOK(mp_init(&meth->irr));
+
+ 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();
+ 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();
+ 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);
+ free(meth);
+}
+
+/* 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));
+ 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));
+ MP_CHECKOK(mp_set_int(&t, 1));
+ MP_CHECKOK(mp_bdivmod(&t, b, &meth->irr, meth->irr_arr, r));
+ CLEANUP:
+ mp_clear(&t);
+ return res;
+ } else {
+ return mp_bdivmod(a, b, &meth->irr, meth->irr_arr, r);
+ }
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecl_mult.c b/mozilla/security/nss/lib/freebl/ecl/ecl_mult.c
new file mode 100644
index 0000000..050d0a7
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecl_mult.c
@@ -0,0 +1,356 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "mpi.h"
+#include "mplogic.h"
+#include "ecl.h"
+#include "ecl-priv.h"
+#include <stdlib.h>
+
+/* 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));
+ 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));
+ MP_CHECKOK(mp_init(&sy));
+
+ 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) );
+ MP_CHECKOK( mp_init_size(&precomp[i][j][1],
+ ECL_MAX_FIELD_SIZE_DIGITS) );
+ }
+ }
+
+ /* 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));
+ 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));
+ 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;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp.h b/mozilla/security/nss/lib/freebl/ecl/ecp.h
new file mode 100644
index 0000000..1d247b1
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp.h
@@ -0,0 +1,140 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __ecp_h_
+#define __ecp_h_
+
+#include "ecl-priv.h"
+
+/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */
+mp_err ec_GFp_pt_is_inf_aff(const mp_int *px, const mp_int *py);
+
+/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */
+mp_err ec_GFp_pt_set_inf_aff(mp_int *px, mp_int *py);
+
+/* Computes R = P + Q where R is (rx, ry), P is (px, py) and Q is (qx,
+ * qy). Uses affine coordinates. */
+mp_err ec_GFp_pt_add_aff(const mp_int *px, const mp_int *py,
+ const mp_int *qx, const mp_int *qy, mp_int *rx,
+ mp_int *ry, const ECGroup *group);
+
+/* Computes R = P - Q. Uses affine coordinates. */
+mp_err ec_GFp_pt_sub_aff(const mp_int *px, const mp_int *py,
+ const mp_int *qx, const mp_int *qy, mp_int *rx,
+ mp_int *ry, const ECGroup *group);
+
+/* Computes R = 2P. Uses affine coordinates. */
+mp_err ec_GFp_pt_dbl_aff(const mp_int *px, const mp_int *py, mp_int *rx,
+ mp_int *ry, const ECGroup *group);
+
+/* Validates a point on a GFp curve. */
+mp_err ec_GFp_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group);
+
+#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
+/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
+ * a, b and p are the elliptic curve coefficients and the prime that
+ * determines the field GFp. Uses affine coordinates. */
+mp_err ec_GFp_pt_mul_aff(const mp_int *n, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *group);
+#endif
+
+/* Converts a point P(px, py) from affine coordinates to Jacobian
+ * projective coordinates R(rx, ry, rz). */
+mp_err ec_GFp_pt_aff2jac(const mp_int *px, const mp_int *py, mp_int *rx,
+ mp_int *ry, mp_int *rz, const ECGroup *group);
+
+/* Converts a point P(px, py, pz) from Jacobian projective coordinates to
+ * affine coordinates R(rx, ry). */
+mp_err ec_GFp_pt_jac2aff(const mp_int *px, const mp_int *py,
+ const mp_int *pz, mp_int *rx, mp_int *ry,
+ const ECGroup *group);
+
+/* Checks if point P(px, py, pz) is at infinity. Uses Jacobian
+ * coordinates. */
+mp_err ec_GFp_pt_is_inf_jac(const mp_int *px, const mp_int *py,
+ const mp_int *pz);
+
+/* Sets P(px, py, pz) to be the point at infinity. Uses Jacobian
+ * coordinates. */
+mp_err ec_GFp_pt_set_inf_jac(mp_int *px, mp_int *py, mp_int *pz);
+
+/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is
+ * (qx, qy, qz). Uses Jacobian coordinates. */
+mp_err ec_GFp_pt_add_jac_aff(const mp_int *px, const mp_int *py,
+ const mp_int *pz, const mp_int *qx,
+ const mp_int *qy, mp_int *rx, mp_int *ry,
+ mp_int *rz, const ECGroup *group);
+
+/* Computes R = 2P. Uses Jacobian coordinates. */
+mp_err ec_GFp_pt_dbl_jac(const mp_int *px, const mp_int *py,
+ const mp_int *pz, mp_int *rx, mp_int *ry,
+ mp_int *rz, const ECGroup *group);
+
+#ifdef ECL_ENABLE_GFP_PT_MUL_JAC
+/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
+ * a, b and p are the elliptic curve coefficients and the prime that
+ * determines the field GFp. Uses Jacobian coordinates. */
+mp_err ec_GFp_pt_mul_jac(const mp_int *n, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *group);
+#endif
+
+/* Computes R(x, y) = k1 * G + k2 * P(x, y), where G is the generator
+ * (base point) of the group of points on the elliptic curve. Allows k1 =
+ * NULL or { k2, P } = NULL. Implemented using mixed Jacobian-affine
+ * coordinates. Input and output values are assumed to be NOT
+ * field-encoded and are in affine form. */
+mp_err
+ ec_GFp_pts_mul_jac(const mp_int *k1, const mp_int *k2, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *group);
+
+/* 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_ */
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_192.c b/mozilla/security/nss/lib/freebl/ecl/ecp_192.c
new file mode 100644
index 0000000..f4cd42b
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_192.c
@@ -0,0 +1,516 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ecp.h"
+#include "mpi.h"
+#include "mplogic.h"
+#include "mpi-priv.h"
+#include <stdlib.h>
+
+#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));
+ MP_CHECKOK(mp_invmod(b, &meth->irr, &t));
+ MP_CHECKOK(mp_mul(a, &t, r));
+ MP_CHECKOK(ec_GFp_nistp192_mod(r, r, meth));
+ CLEANUP:
+ mp_clear(&t);
+ return res;
+ }
+}
+
+/* Wire in fast field arithmetic and precomputation of base point for
+ * named curves. */
+mp_err
+ec_group_set_gfp192(ECGroup *group, ECCurveName name)
+{
+ if (name == ECCurve_NIST_P192) {
+ group->meth->field_mod = &ec_GFp_nistp192_mod;
+ group->meth->field_mul = &ec_GFp_nistp192_mul;
+ group->meth->field_sqr = &ec_GFp_nistp192_sqr;
+ group->meth->field_div = &ec_GFp_nistp192_div;
+#ifndef ECL_THIRTY_TWO_BIT
+ group->meth->field_add = &ec_GFp_nistp192_add;
+ group->meth->field_sub = &ec_GFp_nistp192_sub;
+#endif
+ }
+ return MP_OKAY;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_224.c b/mozilla/security/nss/lib/freebl/ecl/ecp_224.c
new file mode 100644
index 0000000..56683e9
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_224.c
@@ -0,0 +1,372 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ecp.h"
+#include "mpi.h"
+#include "mplogic.h"
+#include "mpi-priv.h"
+#include <stdlib.h>
+
+#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));
+ MP_CHECKOK(mp_invmod(b, &meth->irr, &t));
+ MP_CHECKOK(mp_mul(a, &t, r));
+ MP_CHECKOK(ec_GFp_nistp224_mod(r, r, meth));
+ CLEANUP:
+ mp_clear(&t);
+ return res;
+ }
+}
+
+/* Wire in fast field arithmetic and precomputation of base point for
+ * named curves. */
+mp_err
+ec_group_set_gfp224(ECGroup *group, ECCurveName name)
+{
+ if (name == ECCurve_NIST_P224) {
+ group->meth->field_mod = &ec_GFp_nistp224_mod;
+ group->meth->field_mul = &ec_GFp_nistp224_mul;
+ group->meth->field_sqr = &ec_GFp_nistp224_sqr;
+ group->meth->field_div = &ec_GFp_nistp224_div;
+ }
+ return MP_OKAY;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_256.c b/mozilla/security/nss/lib/freebl/ecl/ecp_256.c
new file mode 100644
index 0000000..15d29ab
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_256.c
@@ -0,0 +1,429 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ecp.h"
+#include "mpi.h"
+#include "mplogic.h"
+#include "mpi-priv.h"
+#include <stdlib.h>
+
+/* 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;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_384.c b/mozilla/security/nss/lib/freebl/ecl/ecp_384.c
new file mode 100644
index 0000000..4ad4137
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_384.c
@@ -0,0 +1,293 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ecp.h"
+#include "mpi.h"
+#include "mplogic.h"
+#include "mpi-priv.h"
+#include <stdlib.h>
+
+/* Fast modular reduction for p384 = 2^384 - 2^128 - 2^96 + 2^32 - 1. a can be r.
+ * Uses algorithm 2.30 from Hankerson, Menezes, Vanstone. Guide to
+ * Elliptic Curve Cryptography. */
+mp_err
+ec_GFp_nistp384_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ int a_bits = mpl_significant_bits(a);
+ int i;
+
+ /* m1, m2 are statically-allocated mp_int of exactly the size we need */
+ mp_int m[10];
+
+#ifdef ECL_THIRTY_TWO_BIT
+ mp_digit s[10][12];
+ for (i = 0; i < 10; i++) {
+ MP_SIGN(&m[i]) = MP_ZPOS;
+ MP_ALLOC(&m[i]) = 12;
+ MP_USED(&m[i]) = 12;
+ MP_DIGITS(&m[i]) = s[i];
+ }
+#else
+ mp_digit s[10][6];
+ for (i = 0; i < 10; i++) {
+ MP_SIGN(&m[i]) = MP_ZPOS;
+ MP_ALLOC(&m[i]) = 6;
+ MP_USED(&m[i]) = 6;
+ MP_DIGITS(&m[i]) = s[i];
+ }
+#endif
+
+#ifdef ECL_THIRTY_TWO_BIT
+ /* for polynomials larger than twice the field size or polynomials
+ * not using all words, use regular reduction */
+ if ((a_bits > 768) || (a_bits <= 736)) {
+ MP_CHECKOK(mp_mod(a, &meth->irr, r));
+ } else {
+ for (i = 0; i < 12; i++) {
+ s[0][i] = MP_DIGIT(a, i);
+ }
+ s[1][0] = 0;
+ s[1][1] = 0;
+ s[1][2] = 0;
+ s[1][3] = 0;
+ s[1][4] = MP_DIGIT(a, 21);
+ s[1][5] = MP_DIGIT(a, 22);
+ s[1][6] = MP_DIGIT(a, 23);
+ s[1][7] = 0;
+ s[1][8] = 0;
+ s[1][9] = 0;
+ s[1][10] = 0;
+ s[1][11] = 0;
+ for (i = 0; i < 12; i++) {
+ s[2][i] = MP_DIGIT(a, i+12);
+ }
+ s[3][0] = MP_DIGIT(a, 21);
+ s[3][1] = MP_DIGIT(a, 22);
+ s[3][2] = MP_DIGIT(a, 23);
+ for (i = 3; i < 12; i++) {
+ s[3][i] = MP_DIGIT(a, i+9);
+ }
+ s[4][0] = 0;
+ s[4][1] = MP_DIGIT(a, 23);
+ s[4][2] = 0;
+ s[4][3] = MP_DIGIT(a, 20);
+ for (i = 4; i < 12; i++) {
+ s[4][i] = MP_DIGIT(a, i+8);
+ }
+ s[5][0] = 0;
+ s[5][1] = 0;
+ s[5][2] = 0;
+ s[5][3] = 0;
+ s[5][4] = MP_DIGIT(a, 20);
+ s[5][5] = MP_DIGIT(a, 21);
+ s[5][6] = MP_DIGIT(a, 22);
+ s[5][7] = MP_DIGIT(a, 23);
+ s[5][8] = 0;
+ s[5][9] = 0;
+ s[5][10] = 0;
+ s[5][11] = 0;
+ s[6][0] = MP_DIGIT(a, 20);
+ s[6][1] = 0;
+ s[6][2] = 0;
+ s[6][3] = MP_DIGIT(a, 21);
+ s[6][4] = MP_DIGIT(a, 22);
+ s[6][5] = MP_DIGIT(a, 23);
+ s[6][6] = 0;
+ s[6][7] = 0;
+ s[6][8] = 0;
+ s[6][9] = 0;
+ s[6][10] = 0;
+ s[6][11] = 0;
+ s[7][0] = MP_DIGIT(a, 23);
+ for (i = 1; i < 12; i++) {
+ s[7][i] = MP_DIGIT(a, i+11);
+ }
+ s[8][0] = 0;
+ s[8][1] = MP_DIGIT(a, 20);
+ s[8][2] = MP_DIGIT(a, 21);
+ s[8][3] = MP_DIGIT(a, 22);
+ s[8][4] = MP_DIGIT(a, 23);
+ s[8][5] = 0;
+ s[8][6] = 0;
+ s[8][7] = 0;
+ s[8][8] = 0;
+ s[8][9] = 0;
+ s[8][10] = 0;
+ s[8][11] = 0;
+ s[9][0] = 0;
+ s[9][1] = 0;
+ s[9][2] = 0;
+ s[9][3] = MP_DIGIT(a, 23);
+ s[9][4] = MP_DIGIT(a, 23);
+ s[9][5] = 0;
+ s[9][6] = 0;
+ s[9][7] = 0;
+ s[9][8] = 0;
+ s[9][9] = 0;
+ s[9][10] = 0;
+ s[9][11] = 0;
+
+ MP_CHECKOK(mp_add(&m[0], &m[1], r));
+ MP_CHECKOK(mp_add(r, &m[1], r));
+ MP_CHECKOK(mp_add(r, &m[2], r));
+ MP_CHECKOK(mp_add(r, &m[3], r));
+ MP_CHECKOK(mp_add(r, &m[4], r));
+ MP_CHECKOK(mp_add(r, &m[5], r));
+ MP_CHECKOK(mp_add(r, &m[6], r));
+ MP_CHECKOK(mp_sub(r, &m[7], r));
+ MP_CHECKOK(mp_sub(r, &m[8], r));
+ MP_CHECKOK(mp_submod(r, &m[9], &meth->irr, r));
+ s_mp_clamp(r);
+ }
+#else
+ /* for polynomials larger than twice the field size or polynomials
+ * not using all words, use regular reduction */
+ if ((a_bits > 768) || (a_bits <= 736)) {
+ MP_CHECKOK(mp_mod(a, &meth->irr, r));
+ } else {
+ for (i = 0; i < 6; i++) {
+ s[0][i] = MP_DIGIT(a, i);
+ }
+ s[1][0] = 0;
+ s[1][1] = 0;
+ s[1][2] = (MP_DIGIT(a, 10) >> 32) | (MP_DIGIT(a, 11) << 32);
+ s[1][3] = MP_DIGIT(a, 11) >> 32;
+ s[1][4] = 0;
+ s[1][5] = 0;
+ for (i = 0; i < 6; i++) {
+ s[2][i] = MP_DIGIT(a, i+6);
+ }
+ s[3][0] = (MP_DIGIT(a, 10) >> 32) | (MP_DIGIT(a, 11) << 32);
+ s[3][1] = (MP_DIGIT(a, 11) >> 32) | (MP_DIGIT(a, 6) << 32);
+ for (i = 2; i < 6; i++) {
+ s[3][i] = (MP_DIGIT(a, i+4) >> 32) | (MP_DIGIT(a, i+5) << 32);
+ }
+ s[4][0] = (MP_DIGIT(a, 11) >> 32) << 32;
+ s[4][1] = MP_DIGIT(a, 10) << 32;
+ for (i = 2; i < 6; i++) {
+ s[4][i] = MP_DIGIT(a, i+4);
+ }
+ s[5][0] = 0;
+ s[5][1] = 0;
+ s[5][2] = MP_DIGIT(a, 10);
+ s[5][3] = MP_DIGIT(a, 11);
+ s[5][4] = 0;
+ s[5][5] = 0;
+ s[6][0] = (MP_DIGIT(a, 10) << 32) >> 32;
+ s[6][1] = (MP_DIGIT(a, 10) >> 32) << 32;
+ s[6][2] = MP_DIGIT(a, 11);
+ s[6][3] = 0;
+ s[6][4] = 0;
+ s[6][5] = 0;
+ s[7][0] = (MP_DIGIT(a, 11) >> 32) | (MP_DIGIT(a, 6) << 32);
+ for (i = 1; i < 6; i++) {
+ s[7][i] = (MP_DIGIT(a, i+5) >> 32) | (MP_DIGIT(a, i+6) << 32);
+ }
+ s[8][0] = MP_DIGIT(a, 10) << 32;
+ s[8][1] = (MP_DIGIT(a, 10) >> 32) | (MP_DIGIT(a, 11) << 32);
+ s[8][2] = MP_DIGIT(a, 11) >> 32;
+ s[8][3] = 0;
+ s[8][4] = 0;
+ s[8][5] = 0;
+ s[9][0] = 0;
+ s[9][1] = (MP_DIGIT(a, 11) >> 32) << 32;
+ s[9][2] = MP_DIGIT(a, 11) >> 32;
+ s[9][3] = 0;
+ s[9][4] = 0;
+ s[9][5] = 0;
+
+ MP_CHECKOK(mp_add(&m[0], &m[1], r));
+ MP_CHECKOK(mp_add(r, &m[1], r));
+ MP_CHECKOK(mp_add(r, &m[2], r));
+ MP_CHECKOK(mp_add(r, &m[3], r));
+ MP_CHECKOK(mp_add(r, &m[4], r));
+ MP_CHECKOK(mp_add(r, &m[5], r));
+ MP_CHECKOK(mp_add(r, &m[6], r));
+ MP_CHECKOK(mp_sub(r, &m[7], r));
+ MP_CHECKOK(mp_sub(r, &m[8], r));
+ MP_CHECKOK(mp_submod(r, &m[9], &meth->irr, r));
+ s_mp_clamp(r);
+ }
+#endif
+
+ CLEANUP:
+ return res;
+}
+
+/* Compute the square of polynomial a, reduce modulo p384. Store the
+ * result in r. r could be a. Uses optimized modular reduction for p384.
+ */
+mp_err
+ec_GFp_nistp384_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+
+ MP_CHECKOK(mp_sqr(a, r));
+ MP_CHECKOK(ec_GFp_nistp384_mod(r, r, meth));
+ CLEANUP:
+ return res;
+}
+
+/* Compute the product of two polynomials a and b, reduce modulo p384.
+ * Store the result in r. r could be a or b; a could be b. Uses
+ * optimized modular reduction for p384. */
+mp_err
+ec_GFp_nistp384_mul(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+
+ MP_CHECKOK(mp_mul(a, b, r));
+ MP_CHECKOK(ec_GFp_nistp384_mod(r, r, meth));
+ CLEANUP:
+ return res;
+}
+
+/* Wire in fast field arithmetic and precomputation of base point for
+ * named curves. */
+mp_err
+ec_group_set_gfp384(ECGroup *group, ECCurveName name)
+{
+ if (name == ECCurve_NIST_P384) {
+ group->meth->field_mod = &ec_GFp_nistp384_mod;
+ group->meth->field_mul = &ec_GFp_nistp384_mul;
+ group->meth->field_sqr = &ec_GFp_nistp384_sqr;
+ }
+ return MP_OKAY;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_521.c b/mozilla/security/nss/lib/freebl/ecl/ecp_521.c
new file mode 100644
index 0000000..685d19b
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_521.c
@@ -0,0 +1,170 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ecp.h"
+#include "mpi.h"
+#include "mplogic.h"
+#include "mpi-priv.h"
+#include <stdlib.h>
+
+#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));
+ MP_CHECKOK(mp_invmod(b, &meth->irr, &t));
+ MP_CHECKOK(mp_mul(a, &t, r));
+ MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth));
+ CLEANUP:
+ mp_clear(&t);
+ return res;
+ }
+}
+
+/* Wire in fast field arithmetic and precomputation of base point for
+ * named curves. */
+mp_err
+ec_group_set_gfp521(ECGroup *group, ECCurveName name)
+{
+ if (name == ECCurve_NIST_P521) {
+ group->meth->field_mod = &ec_GFp_nistp521_mod;
+ group->meth->field_mul = &ec_GFp_nistp521_mul;
+ group->meth->field_sqr = &ec_GFp_nistp521_sqr;
+ group->meth->field_div = &ec_GFp_nistp521_div;
+ }
+ return MP_OKAY;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_aff.c b/mozilla/security/nss/lib/freebl/ecl/ecp_aff.c
new file mode 100644
index 0000000..cda04ed
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_aff.c
@@ -0,0 +1,357 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ecp.h"
+#include "mplogic.h"
+#include <stdlib.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)
+{
+
+ 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));
+ MP_CHECKOK(mp_init(&temp));
+ MP_CHECKOK(mp_init(&tempx));
+ MP_CHECKOK(mp_init(&tempy));
+ /* 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));
+ /* 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));
+ MP_CHECKOK(mp_init(&accr));
+ MP_CHECKOK(mp_init(&tmp));
+ MP_CHECKOK(mp_init(&pxt));
+ MP_CHECKOK(mp_init(&pyt));
+
+ /* 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;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_fp.c b/mozilla/security/nss/lib/freebl/ecl/ecp_fp.c
new file mode 100644
index 0000000..9dcb7b0
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_fp.c
@@ -0,0 +1,568 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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
+ * using floating point operations.
+ *
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ecp_fp.h"
+#include "ecl-priv.h"
+#include <stdlib.h>
+
+/* Performs tidying on a short multi-precision floating point integer (the
+ * lower group->numDoubles floats). */
+void
+ecfp_tidyShort(double *t, const EC_group_fp * group)
+{
+ group->ecfp_tidy(t, group->alpha, group);
+}
+
+/* Performs tidying on only the upper float digits of a multi-precision
+ * floating point integer, i.e. the digits beyond the regular length which
+ * are removed in the reduction step. */
+void
+ecfp_tidyUpper(double *t, const EC_group_fp * group)
+{
+ group->ecfp_tidy(t + group->numDoubles,
+ group->alpha + group->numDoubles, group);
+}
+
+/* Performs a "tidy" operation, which performs carrying, moving excess
+ * bits from one double to the next double, so that the precision of the
+ * doubles is reduced to the regular precision group->doubleBitSize. This
+ * might result in some float digits being negative. Alternative C version
+ * for portability. */
+void
+ecfp_tidy(double *t, const double *alpha, const EC_group_fp * group)
+{
+ double q;
+ int i;
+
+ /* Do carrying */
+ for (i = 0; i < group->numDoubles - 1; i++) {
+ q = t[i] + alpha[i + 1];
+ q -= alpha[i + 1];
+ t[i] -= q;
+ t[i + 1] += q;
+
+ /* If we don't assume that truncation rounding is used, then q
+ * might be 2^n bigger than expected (if it rounds up), then t[0]
+ * could be negative and t[1] 2^n larger than expected. */
+ }
+}
+
+/* Performs a more mathematically precise "tidying" so that each term is
+ * positive. This is slower than the regular tidying, and is used for
+ * conversion from floating point to integer. */
+void
+ecfp_positiveTidy(double *t, const EC_group_fp * group)
+{
+ double q;
+ int i;
+
+ /* Do carrying */
+ for (i = 0; i < group->numDoubles - 1; i++) {
+ /* Subtract beta to force rounding down */
+ q = t[i] - ecfp_beta[i + 1];
+ q += group->alpha[i + 1];
+ q -= group->alpha[i + 1];
+ t[i] -= q;
+ t[i + 1] += q;
+
+ /* Due to subtracting ecfp_beta, we should have each term a
+ * non-negative int */
+ ECFP_ASSERT(t[i] / ecfp_exp[i] ==
+ (unsigned long long) (t[i] / ecfp_exp[i]));
+ ECFP_ASSERT(t[i] >= 0);
+ }
+}
+
+/* Converts from a floating point representation into an mp_int. Expects
+ * that d is already reduced. */
+void
+ecfp_fp2i(mp_int *mpout, double *d, const ECGroup *ecgroup)
+{
+ EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
+ unsigned short i16[(group->primeBitSize + 15) / 16];
+ double q = 1;
+
+#ifdef ECL_THIRTY_TWO_BIT
+ /* TEST uint32_t z = 0; */
+ unsigned int z = 0;
+#else
+ uint64_t z = 0;
+#endif
+ int zBits = 0;
+ int copiedBits = 0;
+ int i = 0;
+ int j = 0;
+
+ mp_digit *out;
+
+ /* Result should always be >= 0, so set sign accordingly */
+ MP_SIGN(mpout) = MP_ZPOS;
+
+ /* Tidy up so we're just dealing with positive numbers */
+ ecfp_positiveTidy(d, group);
+
+ /* We might need to do this reduction step more than once if the
+ * reduction adds smaller terms which carry-over to cause another
+ * reduction. However, this should happen very rarely, if ever,
+ * depending on the elliptic curve. */
+ do {
+ /* Init loop data */
+ z = 0;
+ zBits = 0;
+ q = 1;
+ i = 0;
+ j = 0;
+ copiedBits = 0;
+
+ /* Might have to do a bit more reduction */
+ group->ecfp_singleReduce(d, group);
+
+ /* Grow the size of the mpint if it's too small */
+ s_mp_grow(mpout, group->numInts);
+ MP_USED(mpout) = group->numInts;
+ out = MP_DIGITS(mpout);
+
+ /* Convert double to 16 bit integers */
+ while (copiedBits < group->primeBitSize) {
+ if (zBits < 16) {
+ z += d[i] * q;
+ i++;
+ ECFP_ASSERT(i < (group->primeBitSize + 15) / 16);
+ zBits += group->doubleBitSize;
+ }
+ i16[j] = z;
+ j++;
+ z >>= 16;
+ zBits -= 16;
+ q *= ecfp_twom16;
+ copiedBits += 16;
+ }
+ } while (z != 0);
+
+ /* Convert 16 bit integers to mp_digit */
+#ifdef ECL_THIRTY_TWO_BIT
+ for (i = 0; i < (group->primeBitSize + 15) / 16; i += 2) {
+ *out = 0;
+ if (i + 1 < (group->primeBitSize + 15) / 16) {
+ *out = i16[i + 1];
+ *out <<= 16;
+ }
+ *out++ += i16[i];
+ }
+#else /* 64 bit */
+ for (i = 0; i < (group->primeBitSize + 15) / 16; i += 4) {
+ *out = 0;
+ if (i + 3 < (group->primeBitSize + 15) / 16) {
+ *out = i16[i + 3];
+ *out <<= 16;
+ }
+ if (i + 2 < (group->primeBitSize + 15) / 16) {
+ *out += i16[i + 2];
+ *out <<= 16;
+ }
+ if (i + 1 < (group->primeBitSize + 15) / 16) {
+ *out += i16[i + 1];
+ *out <<= 16;
+ }
+ *out++ += i16[i];
+ }
+#endif
+
+ /* Perform final reduction. mpout should already be the same number
+ * of bits as p, but might not be less than p. Make it so. Since
+ * mpout has the same number of bits as p, and 2p has a larger bit
+ * size, then mpout < 2p, so a single subtraction of p will suffice. */
+ if (mp_cmp(mpout, &ecgroup->meth->irr) >= 0) {
+ mp_sub(mpout, &ecgroup->meth->irr, mpout);
+ }
+
+ /* Shrink the size of the mp_int to the actual used size (required for
+ * mp_cmp_z == 0) */
+ out = MP_DIGITS(mpout);
+ for (i = group->numInts - 1; i > 0; i--) {
+ if (out[i] != 0)
+ break;
+ }
+ MP_USED(mpout) = i + 1;
+
+ /* Should be between 0 and p-1 */
+ ECFP_ASSERT(mp_cmp(mpout, &ecgroup->meth->irr) < 0);
+ ECFP_ASSERT(mp_cmp_z(mpout) >= 0);
+}
+
+/* Converts from an mpint into a floating point representation. */
+void
+ecfp_i2fp(double *out, const mp_int *x, const ECGroup *ecgroup)
+{
+ int i;
+ int j = 0;
+ int size;
+ double shift = 1;
+ mp_digit *in;
+ EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
+
+#ifdef ECL_DEBUG
+ /* if debug mode, convert result back using ecfp_fp2i into cmp, then
+ * compare to x. */
+ mp_int cmp;
+
+ MP_DIGITS(&cmp) = NULL;
+ mp_init(&cmp);
+#endif
+
+ ECFP_ASSERT(group != NULL);
+
+ /* init output to 0 (since we skip over some terms) */
+ for (i = 0; i < group->numDoubles; i++)
+ out[i] = 0;
+ i = 0;
+
+ size = MP_USED(x);
+ in = MP_DIGITS(x);
+
+ /* Copy from int into doubles */
+#ifdef ECL_THIRTY_TWO_BIT
+ while (j < size) {
+ while (group->doubleBitSize * (i + 1) <= 32 * j) {
+ i++;
+ }
+ ECFP_ASSERT(group->doubleBitSize * i <= 32 * j);
+ out[i] = in[j];
+ out[i] *= shift;
+ shift *= ecfp_two32;
+ j++;
+ }
+#else
+ while (j < size) {
+ while (group->doubleBitSize * (i + 1) <= 64 * j) {
+ i++;
+ }
+ ECFP_ASSERT(group->doubleBitSize * i <= 64 * j);
+ out[i] = (in[j] & 0x00000000FFFFFFFF) * shift;
+
+ while (group->doubleBitSize * (i + 1) <= 64 * j + 32) {
+ i++;
+ }
+ ECFP_ASSERT(24 * i <= 64 * j + 32);
+ out[i] = (in[j] & 0xFFFFFFFF00000000) * shift;
+
+ shift *= ecfp_two64;
+ j++;
+ }
+#endif
+ /* Realign bits to match double boundaries */
+ ecfp_tidyShort(out, group);
+
+#ifdef ECL_DEBUG
+ /* Convert result back to mp_int, compare to original */
+ ecfp_fp2i(&cmp, out, ecgroup);
+ ECFP_ASSERT(mp_cmp(&cmp, x) == 0);
+ mp_clear(&cmp);
+#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 prime that
+ * determines the field GFp. Elliptic curve points P and R can be
+ * identical. Uses Jacobian coordinates. Uses 4-bit window method. */
+mp_err
+ec_GFp_point_mul_jac_4w_fp(const mp_int *n, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *ecgroup)
+{
+ mp_err res = MP_OKAY;
+ ecfp_jac_pt precomp[16], r;
+ ecfp_aff_pt p;
+ EC_group_fp *group;
+
+ mp_int rz;
+ int i, ni, d;
+
+ ARGCHK(ecgroup != NULL, MP_BADARG);
+ ARGCHK((n != NULL) && (px != NULL) && (py != NULL), MP_BADARG);
+
+ group = (EC_group_fp *) ecgroup->extra1;
+ MP_DIGITS(&rz) = 0;
+ MP_CHECKOK(mp_init(&rz));
+
+ /* init p, da */
+ ecfp_i2fp(p.x, px, ecgroup);
+ ecfp_i2fp(p.y, py, ecgroup);
+ ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup);
+
+ /* Do precomputation */
+ group->precompute_jac(precomp, &p, group);
+
+ /* Do main body of calculations */
+ d = (mpl_significant_bits(n) + 3) / 4;
+
+ /* R = inf */
+ for (i = 0; i < group->numDoubles; i++) {
+ r.z[i] = 0;
+ }
+
+ 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 */
+ group->pt_dbl_jac(&r, &r, group);
+ group->pt_dbl_jac(&r, &r, group);
+ group->pt_dbl_jac(&r, &r, group);
+ group->pt_dbl_jac(&r, &r, group);
+
+ /* R = R + (ni * P) */
+ group->pt_add_jac(&r, &precomp[ni], &r, group);
+ }
+
+ /* Convert back to integer */
+ ecfp_fp2i(rx, r.x, ecgroup);
+ ecfp_fp2i(ry, r.y, ecgroup);
+ ecfp_fp2i(&rz, r.z, ecgroup);
+
+ /* convert result S to affine coordinates */
+ MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, ecgroup));
+
+ CLEANUP:
+ mp_clear(&rz);
+ return res;
+}
+
+/* Uses mixed Jacobian-affine coordinates to perform a point
+ * multiplication: R = n * P, n scalar. Uses mixed Jacobian-affine
+ * coordinates (Jacobian coordinates for doubles and affine coordinates
+ * for additions; based on recommendation from Brown et al.). Not very
+ * time efficient but quite space efficient, no precomputation needed.
+ * group contains the elliptic curve coefficients and the prime that
+ * determines the field GFp. Elliptic curve points P and R can be
+ * identical. Performs calculations in floating point number format, since
+ * this is faster than the integer operations on the ULTRASPARC III.
+ * Uses left-to-right binary method (double & add) (algorithm 9) 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_jac_fp(const mp_int *n, const mp_int *px, const mp_int *py,
+ mp_int *rx, mp_int *ry, const ECGroup *ecgroup)
+{
+ mp_err res;
+ mp_int sx, sy, sz;
+
+ ecfp_aff_pt p;
+ ecfp_jac_pt r;
+ EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
+
+ int i, l;
+
+ MP_DIGITS(&sx) = 0;
+ MP_DIGITS(&sy) = 0;
+ MP_DIGITS(&sz) = 0;
+ MP_CHECKOK(mp_init(&sx));
+ MP_CHECKOK(mp_init(&sy));
+ MP_CHECKOK(mp_init(&sz));
+
+ /* if n = 0 then r = inf */
+ if (mp_cmp_z(n) == 0) {
+ mp_zero(rx);
+ mp_zero(ry);
+ res = MP_OKAY;
+ goto CLEANUP;
+ /* if n < 0 then out of range error */
+ } else if (mp_cmp_z(n) < 0) {
+ res = MP_RANGE;
+ goto CLEANUP;
+ }
+
+ /* Convert from integer to floating point */
+ ecfp_i2fp(p.x, px, ecgroup);
+ ecfp_i2fp(p.y, py, ecgroup);
+ ecfp_i2fp(group->curvea, &(ecgroup->curvea), ecgroup);
+
+ /* Init r to point at infinity */
+ for (i = 0; i < group->numDoubles; i++) {
+ r.z[i] = 0;
+ }
+
+ /* double and add method */
+ l = mpl_significant_bits(n) - 1;
+
+ for (i = l; i >= 0; i--) {
+ /* R = 2R */
+ group->pt_dbl_jac(&r, &r, group);
+
+ /* if n_i = 1, then R = R + Q */
+ if (MP_GET_BIT(n, i) != 0) {
+ group->pt_add_jac_aff(&r, &p, &r, group);
+ }
+ }
+
+ /* Convert from floating point to integer */
+ ecfp_fp2i(&sx, r.x, ecgroup);
+ ecfp_fp2i(&sy, r.y, ecgroup);
+ ecfp_fp2i(&sz, r.z, ecgroup);
+
+ /* convert result R to affine coordinates */
+ MP_CHECKOK(ec_GFp_pt_jac2aff(&sx, &sy, &sz, rx, ry, ecgroup));
+
+ CLEANUP:
+ mp_clear(&sx);
+ mp_clear(&sy);
+ mp_clear(&sz);
+ 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. 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_point_mul_wNAF_fp(const mp_int *n, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *ecgroup)
+{
+ mp_err res = MP_OKAY;
+ mp_int sx, sy, sz;
+ EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
+ ecfp_chud_pt precomp[16];
+
+ ecfp_aff_pt p;
+ ecfp_jm_pt r;
+
+ signed char naf[group->orderBitSize + 1];
+ int i;
+
+ MP_DIGITS(&sx) = 0;
+ MP_DIGITS(&sy) = 0;
+ MP_DIGITS(&sz) = 0;
+ MP_CHECKOK(mp_init(&sx));
+ MP_CHECKOK(mp_init(&sy));
+ MP_CHECKOK(mp_init(&sz));
+
+ /* if n = 0 then r = inf */
+ if (mp_cmp_z(n) == 0) {
+ mp_zero(rx);
+ mp_zero(ry);
+ res = MP_OKAY;
+ goto CLEANUP;
+ /* if n < 0 then out of range error */
+ } else if (mp_cmp_z(n) < 0) {
+ res = MP_RANGE;
+ goto CLEANUP;
+ }
+
+ /* Convert from integer to floating point */
+ ecfp_i2fp(p.x, px, ecgroup);
+ ecfp_i2fp(p.y, py, ecgroup);
+ ecfp_i2fp(group->curvea, &(ecgroup->curvea), ecgroup);
+
+ /* Perform precomputation */
+ group->precompute_chud(precomp, &p, group);
+
+ /* Compute 5NAF */
+ ec_compute_wNAF(naf, group->orderBitSize, n, 5);
+
+ /* Init R = pt at infinity */
+ for (i = 0; i < group->numDoubles; i++) {
+ r.z[i] = 0;
+ }
+
+ /* wNAF method */
+ for (i = group->orderBitSize; i >= 0; i--) {
+ /* R = 2R */
+ group->pt_dbl_jm(&r, &r, group);
+
+ if (naf[i] != 0) {
+ group->pt_add_jm_chud(&r, &precomp[(naf[i] + 15) / 2], &r,
+ group);
+ }
+ }
+
+ /* Convert from floating point to integer */
+ ecfp_fp2i(&sx, r.x, ecgroup);
+ ecfp_fp2i(&sy, r.y, ecgroup);
+ ecfp_fp2i(&sz, r.z, ecgroup);
+
+ /* convert result R to affine coordinates */
+ MP_CHECKOK(ec_GFp_pt_jac2aff(&sx, &sy, &sz, rx, ry, ecgroup));
+
+ CLEANUP:
+ mp_clear(&sx);
+ mp_clear(&sy);
+ mp_clear(&sz);
+ return res;
+}
+
+/* Cleans up extra memory allocated in ECGroup for this implementation. */
+void
+ec_GFp_extra_free_fp(ECGroup *group)
+{
+ if (group->extra1 != NULL) {
+ free(group->extra1);
+ group->extra1 = NULL;
+ }
+}
+
+/* Tests what precision floating point arithmetic is set to. This should
+ * be either a 53-bit mantissa (IEEE standard) or a 64-bit mantissa
+ * (extended precision on x86) and sets it into the EC_group_fp. Returns
+ * either 53 or 64 accordingly. */
+int
+ec_set_fp_precision(EC_group_fp * group)
+{
+ double a = 9007199254740992.0; /* 2^53 */
+ double b = a + 1;
+
+ if (a == b) {
+ group->fpPrecision = 53;
+ group->alpha = ecfp_alpha_53;
+ return 53;
+ }
+ group->fpPrecision = 64;
+ group->alpha = ecfp_alpha_64;
+ return 64;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_fp.h b/mozilla/security/nss/lib/freebl/ecl/ecp_fp.h
new file mode 100644
index 0000000..8eedeb4
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_fp.h
@@ -0,0 +1,406 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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 using floating point operations.
+ *
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __ecp_fp_h_
+#define __ecp_fp_h_
+
+#include "mpi.h"
+#include "ecl.h"
+#include "ecp.h"
+
+#include <sys/types.h>
+#include "mpi-priv.h"
+
+#ifdef ECL_DEBUG
+#include <assert.h>
+#endif
+
+/* Largest number of doubles to store one reduced number in floating
+ * point. Used for memory allocation on the stack. */
+#define ECFP_MAXDOUBLES 10
+
+/* For debugging purposes */
+#ifndef ECL_DEBUG
+#define ECFP_ASSERT(x)
+#else
+#define ECFP_ASSERT(x) assert(x)
+#endif
+
+/* ECFP_Ti = 2^(i*24) Define as preprocessor constants so we can use in
+ * multiple static constants */
+#define ECFP_T0 1.0
+#define ECFP_T1 16777216.0
+#define ECFP_T2 281474976710656.0
+#define ECFP_T3 4722366482869645213696.0
+#define ECFP_T4 79228162514264337593543950336.0
+#define ECFP_T5 1329227995784915872903807060280344576.0
+#define ECFP_T6 22300745198530623141535718272648361505980416.0
+#define ECFP_T7 374144419156711147060143317175368453031918731001856.0
+#define ECFP_T8 6277101735386680763835789423207666416102355444464034512896.0
+#define ECFP_T9 105312291668557186697918027683670432318895095400549111254310977536.0
+#define ECFP_T10 1766847064778384329583297500742918515827483896875618958121606201292619776.0
+#define ECFP_T11 29642774844752946028434172162224104410437116074403984394101141506025761187823616.0
+#define ECFP_T12 497323236409786642155382248146820840100456150797347717440463976893159497012533375533056.0
+#define ECFP_T13 8343699359066055009355553539724812947666814540455674882605631280555545803830627148527195652096.0
+#define ECFP_T14 139984046386112763159840142535527767382602843577165595931249318810236991948760059086304843329475444736.0
+#define ECFP_T15 2348542582773833227889480596789337027375682548908319870707290971532209025114608443463698998384768703031934976.0
+#define ECFP_T16 39402006196394479212279040100143613805079739270465446667948293404245\
+721771497210611414266254884915640806627990306816.0
+#define ECFP_T17 66105596879024859895191530803277103982840468296428121928464879527440\
+5791236311345825189210439715284847591212025023358304256.0
+#define ECFP_T18 11090678776483259438313656736572334813745748301503266300681918322458\
+485231222502492159897624416558312389564843845614287315896631296.0
+#define ECFP_T19 18607071341967536398062689481932916079453218833595342343206149099024\
+36577570298683715049089827234727835552055312041415509848580169253519\
+36.0
+
+#define ECFP_TWO160 1461501637330902918203684832716283019655932542976.0
+#define ECFP_TWO192 6277101735386680763835789423207666416102355444464034512896.0
+#define ECFP_TWO224 26959946667150639794667015087019630673637144422540572481103610249216.0
+
+/* Multiplicative constants */
+static const double ecfp_two32 = 4294967296.0;
+static const double ecfp_two64 = 18446744073709551616.0;
+static const double ecfp_twom16 = .0000152587890625;
+static const double ecfp_twom128 =
+ .00000000000000000000000000000000000000293873587705571876992184134305561419454666389193021880377187926569604314863681793212890625;
+static const double ecfp_twom129 =
+ .000000000000000000000000000000000000001469367938527859384960920671527807097273331945965109401885939632848021574318408966064453125;
+static const double ecfp_twom160 =
+ .0000000000000000000000000000000000000000000000006842277657836020854119773355907793609766904013068924666782559979930620520927053718196475529111921787261962890625;
+static const double ecfp_twom192 =
+ .000000000000000000000000000000000000000000000000000000000159309191113245227702888039776771180559110455519261878607388585338616290151305816094308987472018268594098344692611135542392730712890625;
+static const double ecfp_twom224 =
+ .00000000000000000000000000000000000000000000000000000000000000000003709206150687421385731735261547639513367564778757791002453039058917581340095629358997312082723208437536338919136001159027049567384892725385725498199462890625;
+
+/* ecfp_exp[i] = 2^(i*ECFP_DSIZE) */
+static const double ecfp_exp[2 * ECFP_MAXDOUBLES] = {
+ ECFP_T0, ECFP_T1, ECFP_T2, ECFP_T3, ECFP_T4, ECFP_T5,
+ ECFP_T6, ECFP_T7, ECFP_T8, ECFP_T9, ECFP_T10, ECFP_T11,
+ ECFP_T12, ECFP_T13, ECFP_T14, ECFP_T15, ECFP_T16, ECFP_T17, ECFP_T18,
+ ECFP_T19
+};
+
+/* 1.1 * 2^52 Uses 2^52 to truncate, the .1 is an extra 2^51 to protect
+ * the 2^52 bit, so that adding alphas to a negative number won't borrow
+ * and empty the important 2^52 bit */
+#define ECFP_ALPHABASE_53 6755399441055744.0
+/* Special case: On some platforms, notably x86 Linux, there is an
+ * extended-precision floating point representation with 64-bits of
+ * precision in the mantissa. These extra bits of precision require a
+ * larger value of alpha to truncate, i.e. 1.1 * 2^63. */
+#define ECFP_ALPHABASE_64 13835058055282163712.0
+
+/*
+ * ecfp_alpha[i] = 1.5 * 2^(52 + i*ECFP_DSIZE) we add and subtract alpha
+ * to truncate floating point numbers to a certain number of bits for
+ * tidying */
+static const double ecfp_alpha_53[2 * ECFP_MAXDOUBLES] = {
+ ECFP_ALPHABASE_53 * ECFP_T0,
+ ECFP_ALPHABASE_53 * ECFP_T1,
+ ECFP_ALPHABASE_53 * ECFP_T2,
+ ECFP_ALPHABASE_53 * ECFP_T3,
+ ECFP_ALPHABASE_53 * ECFP_T4,
+ ECFP_ALPHABASE_53 * ECFP_T5,
+ ECFP_ALPHABASE_53 * ECFP_T6,
+ ECFP_ALPHABASE_53 * ECFP_T7,
+ ECFP_ALPHABASE_53 * ECFP_T8,
+ ECFP_ALPHABASE_53 * ECFP_T9,
+ ECFP_ALPHABASE_53 * ECFP_T10,
+ ECFP_ALPHABASE_53 * ECFP_T11,
+ ECFP_ALPHABASE_53 * ECFP_T12,
+ ECFP_ALPHABASE_53 * ECFP_T13,
+ ECFP_ALPHABASE_53 * ECFP_T14,
+ ECFP_ALPHABASE_53 * ECFP_T15,
+ ECFP_ALPHABASE_53 * ECFP_T16,
+ ECFP_ALPHABASE_53 * ECFP_T17,
+ ECFP_ALPHABASE_53 * ECFP_T18,
+ ECFP_ALPHABASE_53 * ECFP_T19
+};
+
+/*
+ * ecfp_alpha[i] = 1.5 * 2^(63 + i*ECFP_DSIZE) we add and subtract alpha
+ * to truncate floating point numbers to a certain number of bits for
+ * tidying */
+static const double ecfp_alpha_64[2 * ECFP_MAXDOUBLES] = {
+ ECFP_ALPHABASE_64 * ECFP_T0,
+ ECFP_ALPHABASE_64 * ECFP_T1,
+ ECFP_ALPHABASE_64 * ECFP_T2,
+ ECFP_ALPHABASE_64 * ECFP_T3,
+ ECFP_ALPHABASE_64 * ECFP_T4,
+ ECFP_ALPHABASE_64 * ECFP_T5,
+ ECFP_ALPHABASE_64 * ECFP_T6,
+ ECFP_ALPHABASE_64 * ECFP_T7,
+ ECFP_ALPHABASE_64 * ECFP_T8,
+ ECFP_ALPHABASE_64 * ECFP_T9,
+ ECFP_ALPHABASE_64 * ECFP_T10,
+ ECFP_ALPHABASE_64 * ECFP_T11,
+ ECFP_ALPHABASE_64 * ECFP_T12,
+ ECFP_ALPHABASE_64 * ECFP_T13,
+ ECFP_ALPHABASE_64 * ECFP_T14,
+ ECFP_ALPHABASE_64 * ECFP_T15,
+ ECFP_ALPHABASE_64 * ECFP_T16,
+ ECFP_ALPHABASE_64 * ECFP_T17,
+ ECFP_ALPHABASE_64 * ECFP_T18,
+ ECFP_ALPHABASE_64 * ECFP_T19
+};
+
+/* 0.011111111111111111111111 (binary) = 0.5 - 2^25 (24 ones) */
+#define ECFP_BETABASE 0.4999999701976776123046875
+
+/*
+ * We subtract beta prior to using alpha to simulate rounding down. We
+ * make this close to 0.5 to round almost everything down, but exactly 0.5
+ * would cause some incorrect rounding. */
+static const double ecfp_beta[2 * ECFP_MAXDOUBLES] = {
+ ECFP_BETABASE * ECFP_T0,
+ ECFP_BETABASE * ECFP_T1,
+ ECFP_BETABASE * ECFP_T2,
+ ECFP_BETABASE * ECFP_T3,
+ ECFP_BETABASE * ECFP_T4,
+ ECFP_BETABASE * ECFP_T5,
+ ECFP_BETABASE * ECFP_T6,
+ ECFP_BETABASE * ECFP_T7,
+ ECFP_BETABASE * ECFP_T8,
+ ECFP_BETABASE * ECFP_T9,
+ ECFP_BETABASE * ECFP_T10,
+ ECFP_BETABASE * ECFP_T11,
+ ECFP_BETABASE * ECFP_T12,
+ ECFP_BETABASE * ECFP_T13,
+ ECFP_BETABASE * ECFP_T14,
+ ECFP_BETABASE * ECFP_T15,
+ ECFP_BETABASE * ECFP_T16,
+ ECFP_BETABASE * ECFP_T17,
+ ECFP_BETABASE * ECFP_T18,
+ ECFP_BETABASE * ECFP_T19
+};
+
+static const double ecfp_beta_160 = ECFP_BETABASE * ECFP_TWO160;
+static const double ecfp_beta_192 = ECFP_BETABASE * ECFP_TWO192;
+static const double ecfp_beta_224 = ECFP_BETABASE * ECFP_TWO224;
+
+/* Affine EC Point. This is the basic representation (x, y) of an elliptic
+ * curve point. */
+typedef struct {
+ double x[ECFP_MAXDOUBLES];
+ double y[ECFP_MAXDOUBLES];
+} ecfp_aff_pt;
+
+/* Jacobian EC Point. This coordinate system uses X = x/z^2, Y = y/z^3,
+ * which enables calculations with fewer inversions than affine
+ * coordinates. */
+typedef struct {
+ double x[ECFP_MAXDOUBLES];
+ double y[ECFP_MAXDOUBLES];
+ double z[ECFP_MAXDOUBLES];
+} ecfp_jac_pt;
+
+/* Chudnovsky Jacobian EC Point. This coordinate system is the same as
+ * Jacobian, except it keeps z^2, z^3 for faster additions. */
+typedef struct {
+ double x[ECFP_MAXDOUBLES];
+ double y[ECFP_MAXDOUBLES];
+ double z[ECFP_MAXDOUBLES];
+ double z2[ECFP_MAXDOUBLES];
+ double z3[ECFP_MAXDOUBLES];
+} ecfp_chud_pt;
+
+/* Modified Jacobian EC Point. This coordinate system is the same as
+ * Jacobian, except it keeps a*z^4 for faster doublings. */
+typedef struct {
+ double x[ECFP_MAXDOUBLES];
+ double y[ECFP_MAXDOUBLES];
+ double z[ECFP_MAXDOUBLES];
+ double az4[ECFP_MAXDOUBLES];
+} ecfp_jm_pt;
+
+struct EC_group_fp_str;
+
+typedef struct EC_group_fp_str EC_group_fp;
+struct EC_group_fp_str {
+ int fpPrecision; /* Set to number of bits in mantissa, 53
+ * or 64 */
+ int numDoubles;
+ int primeBitSize;
+ int orderBitSize;
+ int doubleBitSize;
+ int numInts;
+ int aIsM3; /* True if curvea == -3 (mod p), then we
+ * can optimize doubling */
+ double curvea[ECFP_MAXDOUBLES];
+ /* Used to truncate a double to the number of bits in the curve */
+ double bitSize_alpha;
+ /* Pointer to either ecfp_alpha_53 or ecfp_alpha_64 */
+ const double *alpha;
+
+ void (*ecfp_singleReduce) (double *r, const EC_group_fp * group);
+ void (*ecfp_reduce) (double *r, double *x, const EC_group_fp * group);
+ /* Performs a "tidy" operation, which performs carrying, moving excess
+ * bits from one double to the next double, so that the precision of
+ * the doubles is reduced to the regular precision ECFP_DSIZE. This
+ * might result in some float digits being negative. */
+ void (*ecfp_tidy) (double *t, const double *alpha,
+ const EC_group_fp * group);
+ /* Perform a point addition using coordinate system Jacobian + Affine
+ * -> Jacobian. Input and output should be multi-precision floating
+ * point integers. */
+ void (*pt_add_jac_aff) (const ecfp_jac_pt * p, const ecfp_aff_pt * q,
+ ecfp_jac_pt * r, const EC_group_fp * group);
+ /* Perform a point doubling in Jacobian coordinates. Input and output
+ * should be multi-precision floating point integers. */
+ void (*pt_dbl_jac) (const ecfp_jac_pt * dp, ecfp_jac_pt * dr,
+ const EC_group_fp * group);
+ /* Perform a point addition using Jacobian coordinate system. Input
+ * and output should be multi-precision floating point integers. */
+ void (*pt_add_jac) (const ecfp_jac_pt * p, const ecfp_jac_pt * q,
+ ecfp_jac_pt * r, const EC_group_fp * group);
+ /* Perform a point doubling in Modified Jacobian coordinates. Input
+ * and output should be multi-precision floating point integers. */
+ void (*pt_dbl_jm) (const ecfp_jm_pt * p, ecfp_jm_pt * r,
+ const EC_group_fp * group);
+ /* Perform a point doubling using coordinates Affine -> Chudnovsky
+ * Jacobian. Input and output should be multi-precision floating point
+ * integers. */
+ void (*pt_dbl_aff2chud) (const ecfp_aff_pt * p, ecfp_chud_pt * r,
+ const EC_group_fp * group);
+ /* Perform a point addition using coordinates: Modified Jacobian +
+ * Chudnovsky Jacobian -> Modified Jacobian. Input and output should
+ * be multi-precision floating point integers. */
+ void (*pt_add_jm_chud) (ecfp_jm_pt * p, ecfp_chud_pt * q,
+ ecfp_jm_pt * r, const EC_group_fp * group);
+ /* Perform a point addition using Chudnovsky Jacobian coordinates.
+ * Input and output should be multi-precision floating point integers.
+ */
+ void (*pt_add_chud) (const ecfp_chud_pt * p, const ecfp_chud_pt * q,
+ ecfp_chud_pt * r, const EC_group_fp * group);
+ /* Expects out to be an array of size 16 of Chudnovsky Jacobian
+ * points. Fills in Chudnovsky Jacobian form (x, y, z, z^2, z^3), for
+ * -15P, -13P, -11P, -9P, -7P, -5P, -3P, -P, P, 3P, 5P, 7P, 9P, 11P,
+ * 13P, 15P */
+ void (*precompute_chud) (ecfp_chud_pt * out, const ecfp_aff_pt * p,
+ const EC_group_fp * group);
+ /* Expects out to be an array of size 16 of Jacobian points. Fills in
+ * Chudnovsky Jacobian form (x, y, z), for O, P, 2P, ... 15P */
+ void (*precompute_jac) (ecfp_jac_pt * out, const ecfp_aff_pt * p,
+ const EC_group_fp * group);
+
+};
+
+/* Computes r = x*y.
+ * r must be different (point to different memory) than x and y.
+ * Does not tidy or reduce. */
+void ecfp_multiply(double *r, const double *x, const double *y);
+
+/* Performs a "tidy" operation, which performs carrying, moving excess
+ * bits from one double to the next double, so that the precision of the
+ * doubles is reduced to the regular precision group->doubleBitSize. This
+ * might result in some float digits being negative. */
+void ecfp_tidy(double *t, const double *alpha, const EC_group_fp * group);
+
+/* Performs tidying on only the upper float digits of a multi-precision
+ * floating point integer, i.e. the digits beyond the regular length which
+ * are removed in the reduction step. */
+void ecfp_tidyUpper(double *t, const EC_group_fp * group);
+
+/* Performs tidying on a short multi-precision floating point integer (the
+ * lower group->numDoubles floats). */
+void ecfp_tidyShort(double *t, const EC_group_fp * group);
+
+/* Performs a more mathematically precise "tidying" so that each term is
+ * positive. This is slower than the regular tidying, and is used for
+ * conversion from floating point to integer. */
+void ecfp_positiveTidy(double *t, const EC_group_fp * 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 GFp. Elliptic curve points P and R can be
+ * identical. Uses mixed Jacobian-affine coordinates. Uses 4-bit window
+ * method. */
+mp_err
+ ec_GFp_point_mul_jac_4w_fp(const mp_int *n, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *ecgroup);
+
+/* Computes R = nP where R is (rx, ry) and P is the base point. 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 (Jacobian
+ * coordinates for doubles and affine coordinates for additions; based on
+ * recommendation from Brown et al.). Uses 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_point_mul_wNAF_fp(const mp_int *n, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *ecgroup);
+
+/* Uses mixed Jacobian-affine coordinates to perform a point
+ * multiplication: R = n * P, n scalar. Uses mixed Jacobian-affine
+ * coordinates (Jacobian coordinates for doubles and affine coordinates
+ * for additions; based on recommendation from Brown et al.). Not very
+ * time efficient but quite space efficient, no precomputation needed.
+ * group contains the elliptic curve coefficients and the prime that
+ * determines the field GFp. Elliptic curve points P and R can be
+ * identical. Performs calculations in floating point number format, since
+ * this is faster than the integer operations on the ULTRASPARC III.
+ * Uses left-to-right binary method (double & add) (algorithm 9) 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_jac_fp(const mp_int *n, const mp_int *px, const mp_int *py,
+ mp_int *rx, mp_int *ry, const ECGroup *ecgroup);
+
+/* Cleans up extra memory allocated in ECGroup for this implementation. */
+void ec_GFp_extra_free_fp(ECGroup *group);
+
+/* Converts from a floating point representation into an mp_int. Expects
+ * that d is already reduced. */
+void
+ ecfp_fp2i(mp_int *mpout, double *d, const ECGroup *ecgroup);
+
+/* Converts from an mpint into a floating point representation. */
+void
+ ecfp_i2fp(double *out, const mp_int *x, const ECGroup *ecgroup);
+
+/* Tests what precision floating point arithmetic is set to. This should
+ * be either a 53-bit mantissa (IEEE standard) or a 64-bit mantissa
+ * (extended precision on x86) and sets it into the EC_group_fp. Returns
+ * either 53 or 64 accordingly. */
+int ec_set_fp_precision(EC_group_fp * group);
+
+#endif
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_fp160.c b/mozilla/security/nss/lib/freebl/ecl/ecp_fp160.c
new file mode 100644
index 0000000..8721579
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_fp160.c
@@ -0,0 +1,179 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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 using floating point operations.
+ *
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ecp_fp.h"
+#include <stdlib.h>
+
+#define ECFP_BSIZE 160
+#define ECFP_NUMDOUBLES 7
+
+#include "ecp_fpinc.c"
+
+/* Performs a single step of reduction, just on the uppermost float
+ * (assumes already tidied), and then retidies. Note, this does not
+ * guarantee that the result will be less than p, but truncates the number
+ * of bits. */
+void
+ecfp160_singleReduce(double *d, const EC_group_fp * group)
+{
+ double q;
+
+ ECFP_ASSERT(group->doubleBitSize == 24);
+ ECFP_ASSERT(group->primeBitSize == 160);
+ ECFP_ASSERT(ECFP_NUMDOUBLES == 7);
+
+ q = d[ECFP_NUMDOUBLES - 1] - ecfp_beta_160;
+ q += group->bitSize_alpha;
+ q -= group->bitSize_alpha;
+
+ d[ECFP_NUMDOUBLES - 1] -= q;
+ d[0] += q * ecfp_twom160;
+ d[1] += q * ecfp_twom129;
+ ecfp_positiveTidy(d, group);
+
+ /* Assertions for the highest order term */
+ ECFP_ASSERT(d[ECFP_NUMDOUBLES - 1] / ecfp_exp[ECFP_NUMDOUBLES - 1] ==
+ (unsigned long long) (d[ECFP_NUMDOUBLES - 1] /
+ ecfp_exp[ECFP_NUMDOUBLES - 1]));
+ ECFP_ASSERT(d[ECFP_NUMDOUBLES - 1] >= 0);
+}
+
+/* Performs imperfect reduction. This might leave some negative terms,
+ * and one more reduction might be required for the result to be between 0
+ * and p-1. x should not already be reduced, i.e. should have
+ * 2*ECFP_NUMDOUBLES significant terms. x and r can be the same, but then
+ * the upper parts of r are not zeroed */
+void
+ecfp160_reduce(double *r, double *x, const EC_group_fp * group)
+{
+
+ double x7, x8, q;
+
+ ECFP_ASSERT(group->doubleBitSize == 24);
+ ECFP_ASSERT(group->primeBitSize == 160);
+ ECFP_ASSERT(ECFP_NUMDOUBLES == 7);
+
+ /* Tidy just the upper bits, the lower bits can wait. */
+ ecfp_tidyUpper(x, group);
+
+ /* Assume that this is already tidied so that we have enough extra
+ * bits */
+ x7 = x[7] + x[13] * ecfp_twom129; /* adds bits 15-39 */
+
+ /* Tidy x7, or we won't have enough bits later to add it in */
+ q = x7 + group->alpha[8];
+ q -= group->alpha[8];
+ x7 -= q; /* holds bits 0-24 */
+ x8 = x[8] + q; /* holds bits 0-25 */
+
+ r[6] = x[6] + x[13] * ecfp_twom160 + x[12] * ecfp_twom129; /* adds
+ * bits
+ * 8-39 */
+ r[5] = x[5] + x[12] * ecfp_twom160 + x[11] * ecfp_twom129;
+ r[4] = x[4] + x[11] * ecfp_twom160 + x[10] * ecfp_twom129;
+ r[3] = x[3] + x[10] * ecfp_twom160 + x[9] * ecfp_twom129;
+ r[2] = x[2] + x[9] * ecfp_twom160 + x8 * ecfp_twom129; /* adds bits
+ * 8-40 */
+ r[1] = x[1] + x8 * ecfp_twom160 + x7 * ecfp_twom129; /* adds bits
+ * 8-39 */
+ r[0] = x[0] + x7 * ecfp_twom160;
+
+ /* Tidy up just r[ECFP_NUMDOUBLES-2] so that the number of reductions
+ * is accurate plus or minus one. (Rather than tidy all to make it
+ * totally accurate, which is more costly.) */
+ q = r[ECFP_NUMDOUBLES - 2] + group->alpha[ECFP_NUMDOUBLES - 1];
+ q -= group->alpha[ECFP_NUMDOUBLES - 1];
+ r[ECFP_NUMDOUBLES - 2] -= q;
+ r[ECFP_NUMDOUBLES - 1] += q;
+
+ /* Tidy up the excess bits on r[ECFP_NUMDOUBLES-1] using reduction */
+ /* Use ecfp_beta so we get a positive result */
+ q = r[ECFP_NUMDOUBLES - 1] - ecfp_beta_160;
+ q += group->bitSize_alpha;
+ q -= group->bitSize_alpha;
+
+ r[ECFP_NUMDOUBLES - 1] -= q;
+ r[0] += q * ecfp_twom160;
+ r[1] += q * ecfp_twom129;
+
+ /* Tidy the result */
+ ecfp_tidyShort(r, group);
+}
+
+/* Sets group to use optimized calculations in this file */
+mp_err
+ec_group_set_secp160r1_fp(ECGroup *group)
+{
+
+ EC_group_fp *fpg = NULL;
+
+ /* Allocate memory for floating point group data */
+ fpg = (EC_group_fp *) malloc(sizeof(EC_group_fp));
+ if (fpg == NULL) {
+ return MP_MEM;
+ }
+
+ fpg->numDoubles = ECFP_NUMDOUBLES;
+ fpg->primeBitSize = ECFP_BSIZE;
+ fpg->orderBitSize = 161;
+ fpg->doubleBitSize = 24;
+ fpg->numInts = (ECFP_BSIZE + ECL_BITS - 1) / ECL_BITS;
+ fpg->aIsM3 = 1;
+ fpg->ecfp_singleReduce = &ecfp160_singleReduce;
+ fpg->ecfp_reduce = &ecfp160_reduce;
+ fpg->ecfp_tidy = &ecfp_tidy;
+
+ fpg->pt_add_jac_aff = &ecfp160_pt_add_jac_aff;
+ fpg->pt_add_jac = &ecfp160_pt_add_jac;
+ fpg->pt_add_jm_chud = &ecfp160_pt_add_jm_chud;
+ fpg->pt_add_chud = &ecfp160_pt_add_chud;
+ fpg->pt_dbl_jac = &ecfp160_pt_dbl_jac;
+ fpg->pt_dbl_jm = &ecfp160_pt_dbl_jm;
+ fpg->pt_dbl_aff2chud = &ecfp160_pt_dbl_aff2chud;
+ fpg->precompute_chud = &ecfp160_precompute_chud;
+ fpg->precompute_jac = &ecfp160_precompute_jac;
+
+ group->point_mul = &ec_GFp_point_mul_wNAF_fp;
+ group->points_mul = &ec_pts_mul_basic;
+ group->extra1 = fpg;
+ group->extra_free = &ec_GFp_extra_free_fp;
+
+ ec_set_fp_precision(fpg);
+ fpg->bitSize_alpha = ECFP_TWO160 * fpg->alpha[0];
+ return MP_OKAY;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_fp192.c b/mozilla/security/nss/lib/freebl/ecl/ecp_fp192.c
new file mode 100644
index 0000000..b5ee533
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_fp192.c
@@ -0,0 +1,177 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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 using floating point operations.
+ *
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ecp_fp.h"
+#include <stdlib.h>
+
+#define ECFP_BSIZE 192
+#define ECFP_NUMDOUBLES 8
+
+#include "ecp_fpinc.c"
+
+/* Performs a single step of reduction, just on the uppermost float
+ * (assumes already tidied), and then retidies. Note, this does not
+ * guarantee that the result will be less than p. */
+void
+ecfp192_singleReduce(double *d, const EC_group_fp * group)
+{
+ double q;
+
+ ECFP_ASSERT(group->doubleBitSize == 24);
+ ECFP_ASSERT(group->primeBitSize == 192);
+ ECFP_ASSERT(group->numDoubles == 8);
+
+ q = d[ECFP_NUMDOUBLES - 1] - ecfp_beta_192;
+ q += group->bitSize_alpha;
+ q -= group->bitSize_alpha;
+
+ d[ECFP_NUMDOUBLES - 1] -= q;
+ d[0] += q * ecfp_twom192;
+ d[2] += q * ecfp_twom128;
+ ecfp_positiveTidy(d, group);
+}
+
+/*
+ * Performs imperfect reduction. This might leave some negative terms,
+ * and one more reduction might be required for the result to be between 0
+ * and p-1. x should be be an array of at least 16, and r at least 8 x and
+ * r can be the same, but then the upper parts of r are not zeroed */
+void
+ecfp_reduce_192(double *r, double *x, const EC_group_fp * group)
+{
+ double x8, x9, x10, q;
+
+ ECFP_ASSERT(group->doubleBitSize == 24);
+ ECFP_ASSERT(group->primeBitSize == 192);
+ ECFP_ASSERT(group->numDoubles == 8);
+
+ /* Tidy just the upper portion, the lower part can wait */
+ ecfp_tidyUpper(x, group);
+
+ x8 = x[8] + x[14] * ecfp_twom128; /* adds bits 16-40 */
+ x9 = x[9] + x[15] * ecfp_twom128; /* adds bits 16-40 */
+
+ /* Tidy up, or we won't have enough bits later to add it in */
+
+ q = x8 + group->alpha[9];
+ q -= group->alpha[9];
+ x8 -= q;
+ x9 += q;
+
+ q = x9 + group->alpha[10];
+ q -= group->alpha[10];
+ x9 -= q;
+ x10 = x[10] + q;
+
+ r[7] = x[7] + x[15] * ecfp_twom192 + x[13] * ecfp_twom128; /* adds
+ * bits
+ * 0-40 */
+ r[6] = x[6] + x[14] * ecfp_twom192 + x[12] * ecfp_twom128;
+ r[5] = x[5] + x[13] * ecfp_twom192 + x[11] * ecfp_twom128;
+ r[4] = x[4] + x[12] * ecfp_twom192 + x10 * ecfp_twom128;
+ r[3] = x[3] + x[11] * ecfp_twom192 + x9 * ecfp_twom128; /* adds bits
+ * 0-40 */
+ r[2] = x[2] + x10 * ecfp_twom192 + x8 * ecfp_twom128;
+ r[1] = x[1] + x9 * ecfp_twom192; /* adds bits 16-40 */
+ r[0] = x[0] + x8 * ecfp_twom192;
+
+ /*
+ * Tidy up just r[group->numDoubles-2] so that the number of
+ * reductions is accurate plus or minus one. (Rather than tidy all to
+ * make it totally accurate) */
+ q = r[ECFP_NUMDOUBLES - 2] + group->alpha[ECFP_NUMDOUBLES - 1];
+ q -= group->alpha[ECFP_NUMDOUBLES - 1];
+ r[ECFP_NUMDOUBLES - 2] -= q;
+ r[ECFP_NUMDOUBLES - 1] += q;
+
+ /* Tidy up the excess bits on r[group->numDoubles-1] using reduction */
+ /* Use ecfp_beta so we get a positive res */
+ q = r[ECFP_NUMDOUBLES - 1] - ecfp_beta_192;
+ q += group->bitSize_alpha;
+ q -= group->bitSize_alpha;
+
+ r[ECFP_NUMDOUBLES - 1] -= q;
+ r[0] += q * ecfp_twom192;
+ r[2] += q * ecfp_twom128;
+
+ /* Tidy the result */
+ ecfp_tidyShort(r, group);
+}
+
+/* Sets group to use optimized calculations in this file */
+mp_err
+ec_group_set_nistp192_fp(ECGroup *group)
+{
+ EC_group_fp *fpg;
+
+ /* Allocate memory for floating point group data */
+ fpg = (EC_group_fp *) malloc(sizeof(EC_group_fp));
+ if (fpg == NULL) {
+ return MP_MEM;
+ }
+
+ fpg->numDoubles = ECFP_NUMDOUBLES;
+ fpg->primeBitSize = ECFP_BSIZE;
+ fpg->orderBitSize = 192;
+ fpg->doubleBitSize = 24;
+ fpg->numInts = (ECFP_BSIZE + ECL_BITS - 1) / ECL_BITS;
+ fpg->aIsM3 = 1;
+ fpg->ecfp_singleReduce = &ecfp192_singleReduce;
+ fpg->ecfp_reduce = &ecfp_reduce_192;
+ fpg->ecfp_tidy = &ecfp_tidy;
+
+ fpg->pt_add_jac_aff = &ecfp192_pt_add_jac_aff;
+ fpg->pt_add_jac = &ecfp192_pt_add_jac;
+ fpg->pt_add_jm_chud = &ecfp192_pt_add_jm_chud;
+ fpg->pt_add_chud = &ecfp192_pt_add_chud;
+ fpg->pt_dbl_jac = &ecfp192_pt_dbl_jac;
+ fpg->pt_dbl_jm = &ecfp192_pt_dbl_jm;
+ fpg->pt_dbl_aff2chud = &ecfp192_pt_dbl_aff2chud;
+ fpg->precompute_chud = &ecfp192_precompute_chud;
+ fpg->precompute_jac = &ecfp192_precompute_jac;
+
+ group->point_mul = &ec_GFp_point_mul_wNAF_fp;
+ group->points_mul = &ec_pts_mul_basic;
+ group->extra1 = fpg;
+ group->extra_free = &ec_GFp_extra_free_fp;
+
+ ec_set_fp_precision(fpg);
+ fpg->bitSize_alpha = ECFP_TWO192 * fpg->alpha[0];
+
+ return MP_OKAY;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_fp224.c b/mozilla/security/nss/lib/freebl/ecl/ecp_fp224.c
new file mode 100644
index 0000000..e1ee536
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_fp224.c
@@ -0,0 +1,190 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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 using floating point operations.
+ *
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ecp_fp.h"
+#include <stdlib.h>
+
+#define ECFP_BSIZE 224
+#define ECFP_NUMDOUBLES 10
+
+#include "ecp_fpinc.c"
+
+/* Performs a single step of reduction, just on the uppermost float
+ * (assumes already tidied), and then retidies. Note, this does not
+ * guarantee that the result will be less than p. */
+void
+ecfp224_singleReduce(double *r, const EC_group_fp * group)
+{
+ double q;
+
+ ECFP_ASSERT(group->doubleBitSize == 24);
+ ECFP_ASSERT(group->primeBitSize == 224);
+ ECFP_ASSERT(group->numDoubles == 10);
+
+ q = r[ECFP_NUMDOUBLES - 1] - ecfp_beta_224;
+ q += group->bitSize_alpha;
+ q -= group->bitSize_alpha;
+
+ r[ECFP_NUMDOUBLES - 1] -= q;
+ r[0] -= q * ecfp_twom224;
+ r[4] += q * ecfp_twom128;
+
+ ecfp_positiveTidy(r, group);
+}
+
+/*
+ * Performs imperfect reduction. This might leave some negative terms,
+ * and one more reduction might be required for the result to be between 0
+ * and p-1. x should be be an array of at least 20, and r at least 10 x
+ * and r can be the same, but then the upper parts of r are not zeroed */
+void
+ecfp224_reduce(double *r, double *x, const EC_group_fp * group)
+{
+
+ double x10, x11, x12, x13, x14, q;
+
+ ECFP_ASSERT(group->doubleBitSize == 24);
+ ECFP_ASSERT(group->primeBitSize == 224);
+ ECFP_ASSERT(group->numDoubles == 10);
+
+ /* Tidy just the upper bits of x. Don't need to tidy the lower ones
+ * yet. */
+ ecfp_tidyUpper(x, group);
+
+ x10 = x[10] + x[16] * ecfp_twom128;
+ x11 = x[11] + x[17] * ecfp_twom128;
+ x12 = x[12] + x[18] * ecfp_twom128;
+ x13 = x[13] + x[19] * ecfp_twom128;
+
+ /* Tidy up, or we won't have enough bits later to add it in */
+ q = x10 + group->alpha[11];
+ q -= group->alpha[11];
+ x10 -= q;
+ x11 = x11 + q;
+
+ q = x11 + group->alpha[12];
+ q -= group->alpha[12];
+ x11 -= q;
+ x12 = x12 + q;
+
+ q = x12 + group->alpha[13];
+ q -= group->alpha[13];
+ x12 -= q;
+ x13 = x13 + q;
+
+ q = x13 + group->alpha[14];
+ q -= group->alpha[14];
+ x13 -= q;
+ x14 = x[14] + q;
+
+ r[9] = x[9] + x[15] * ecfp_twom128 - x[19] * ecfp_twom224;
+ r[8] = x[8] + x14 * ecfp_twom128 - x[18] * ecfp_twom224;
+ r[7] = x[7] + x13 * ecfp_twom128 - x[17] * ecfp_twom224;
+ r[6] = x[6] + x12 * ecfp_twom128 - x[16] * ecfp_twom224;
+ r[5] = x[5] + x11 * ecfp_twom128 - x[15] * ecfp_twom224;
+ r[4] = x[4] + x10 * ecfp_twom128 - x14 * ecfp_twom224;
+ r[3] = x[3] - x13 * ecfp_twom224;
+ r[2] = x[2] - x12 * ecfp_twom224;
+ r[1] = x[1] - x11 * ecfp_twom224;
+ r[0] = x[0] - x10 * ecfp_twom224;
+
+ /*
+ * Tidy up just r[ECFP_NUMDOUBLES-2] so that the number of reductions
+ * is accurate plus or minus one. (Rather than tidy all to make it
+ * totally accurate) */
+ q = r[ECFP_NUMDOUBLES - 2] + group->alpha[ECFP_NUMDOUBLES - 1];
+ q -= group->alpha[ECFP_NUMDOUBLES - 1];
+ r[ECFP_NUMDOUBLES - 2] -= q;
+ r[ECFP_NUMDOUBLES - 1] += q;
+
+ /* Tidy up the excess bits on r[ECFP_NUMDOUBLES-1] using reduction */
+ /* Use ecfp_beta so we get a positive res */
+ q = r[ECFP_NUMDOUBLES - 1] - ecfp_beta_224;
+ q += group->bitSize_alpha;
+ q -= group->bitSize_alpha;
+
+ r[ECFP_NUMDOUBLES - 1] -= q;
+ r[0] -= q * ecfp_twom224;
+ r[4] += q * ecfp_twom128;
+
+ ecfp_tidyShort(r, group);
+}
+
+/* Sets group to use optimized calculations in this file */
+mp_err
+ec_group_set_nistp224_fp(ECGroup *group)
+{
+
+ EC_group_fp *fpg;
+
+ /* Allocate memory for floating point group data */
+ fpg = (EC_group_fp *) malloc(sizeof(EC_group_fp));
+ if (fpg == NULL) {
+ return MP_MEM;
+ }
+
+ fpg->numDoubles = ECFP_NUMDOUBLES;
+ fpg->primeBitSize = ECFP_BSIZE;
+ fpg->orderBitSize = 224;
+ fpg->doubleBitSize = 24;
+ fpg->numInts = (ECFP_BSIZE + ECL_BITS - 1) / ECL_BITS;
+ fpg->aIsM3 = 1;
+ fpg->ecfp_singleReduce = &ecfp224_singleReduce;
+ fpg->ecfp_reduce = &ecfp224_reduce;
+ fpg->ecfp_tidy = &ecfp_tidy;
+
+ fpg->pt_add_jac_aff = &ecfp224_pt_add_jac_aff;
+ fpg->pt_add_jac = &ecfp224_pt_add_jac;
+ fpg->pt_add_jm_chud = &ecfp224_pt_add_jm_chud;
+ fpg->pt_add_chud = &ecfp224_pt_add_chud;
+ fpg->pt_dbl_jac = &ecfp224_pt_dbl_jac;
+ fpg->pt_dbl_jm = &ecfp224_pt_dbl_jm;
+ fpg->pt_dbl_aff2chud = &ecfp224_pt_dbl_aff2chud;
+ fpg->precompute_chud = &ecfp224_precompute_chud;
+ fpg->precompute_jac = &ecfp224_precompute_jac;
+
+ group->point_mul = &ec_GFp_point_mul_wNAF_fp;
+ group->points_mul = &ec_pts_mul_basic;
+ group->extra1 = fpg;
+ group->extra_free = &ec_GFp_extra_free_fp;
+
+ ec_set_fp_precision(fpg);
+ fpg->bitSize_alpha = ECFP_TWO224 * fpg->alpha[0];
+
+ return MP_OKAY;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_fpinc.c b/mozilla/security/nss/lib/freebl/ecl/ecp_fpinc.c
new file mode 100644
index 0000000..61b16ff
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_fpinc.c
@@ -0,0 +1,855 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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 using floating point operations.
+ *
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* This source file is meant to be included by other source files
+ * (ecp_fp###.c, where ### is one of 160, 192, 224) and should not
+ * constitute an independent compilation unit. It requires the following
+ * preprocessor definitions be made: ECFP_BSIZE - the number of bits in
+ * the field's prime
+ * ECFP_NUMDOUBLES - the number of doubles to store one
+ * multi-precision integer in floating point
+
+/* Adds a prefix to a given token to give a unique token name. Prefixes
+ * with "ecfp" + ECFP_BSIZE + "_". e.g. if ECFP_BSIZE = 160, then
+ * PREFIX(hello) = ecfp160_hello This optimization allows static function
+ * linking and compiler loop unrolling without code duplication. */
+#ifndef PREFIX
+#define PREFIX(b) PREFIX1(ECFP_BSIZE, b)
+#define PREFIX1(bsize, b) PREFIX2(bsize, b)
+#define PREFIX2(bsize, b) ecfp ## bsize ## _ ## b
+#endif
+
+/* Returns true iff every double in d is 0. (If d == 0 and it is tidied,
+ * this will be true.) */
+mp_err PREFIX(isZero) (const double *d) {
+ int i;
+
+ for (i = 0; i < ECFP_NUMDOUBLES; i++) {
+ if (d[i] != 0)
+ return MP_NO;
+ }
+ return MP_YES;
+}
+
+/* Sets the multi-precision floating point number at t = 0 */
+void PREFIX(zero) (double *t) {
+ int i;
+
+ for (i = 0; i < ECFP_NUMDOUBLES; i++) {
+ t[i] = 0;
+ }
+}
+
+/* Sets the multi-precision floating point number at t = 1 */
+void PREFIX(one) (double *t) {
+ int i;
+
+ t[0] = 1;
+ for (i = 1; i < ECFP_NUMDOUBLES; i++) {
+ t[i] = 0;
+ }
+}
+
+/* Checks if point P(x, y, z) is at infinity. Uses Jacobian coordinates. */
+mp_err PREFIX(pt_is_inf_jac) (const ecfp_jac_pt * p) {
+ return PREFIX(isZero) (p->z);
+}
+
+/* Sets the Jacobian point P to be at infinity. */
+void PREFIX(set_pt_inf_jac) (ecfp_jac_pt * p) {
+ PREFIX(zero) (p->z);
+}
+
+/* Checks if point P(x, y) is at infinity. Uses Affine coordinates. */
+mp_err PREFIX(pt_is_inf_aff) (const ecfp_aff_pt * p) {
+ if (PREFIX(isZero) (p->x) == MP_YES && PREFIX(isZero) (p->y) == MP_YES)
+ return MP_YES;
+ return MP_NO;
+}
+
+/* Sets the affine point P to be at infinity. */
+void PREFIX(set_pt_inf_aff) (ecfp_aff_pt * p) {
+ PREFIX(zero) (p->x);
+ PREFIX(zero) (p->y);
+}
+
+/* Checks if point P(x, y, z, a*z^4) is at infinity. Uses Modified
+ * Jacobian coordinates. */
+mp_err PREFIX(pt_is_inf_jm) (const ecfp_jm_pt * p) {
+ return PREFIX(isZero) (p->z);
+}
+
+/* Sets the Modified Jacobian point P to be at infinity. */
+void PREFIX(set_pt_inf_jm) (ecfp_jm_pt * p) {
+ PREFIX(zero) (p->z);
+}
+
+/* Checks if point P(x, y, z, z^2, z^3) is at infinity. Uses Chudnovsky
+ * Jacobian coordinates */
+mp_err PREFIX(pt_is_inf_chud) (const ecfp_chud_pt * p) {
+ return PREFIX(isZero) (p->z);
+}
+
+/* Sets the Chudnovsky Jacobian point P to be at infinity. */
+void PREFIX(set_pt_inf_chud) (ecfp_chud_pt * p) {
+ PREFIX(zero) (p->z);
+}
+
+/* Copies a multi-precision floating point number, Setting dest = src */
+void PREFIX(copy) (double *dest, const double *src) {
+ int i;
+
+ for (i = 0; i < ECFP_NUMDOUBLES; i++) {
+ dest[i] = src[i];
+ }
+}
+
+/* Sets dest = -src */
+void PREFIX(negLong) (double *dest, const double *src) {
+ int i;
+
+ for (i = 0; i < 2 * ECFP_NUMDOUBLES; i++) {
+ dest[i] = -src[i];
+ }
+}
+
+/* Sets r = -p p = (x, y, z, z2, z3) r = (x, -y, z, z2, z3) Uses
+ * Chudnovsky Jacobian coordinates. */
+/* TODO reverse order */
+void PREFIX(pt_neg_chud) (const ecfp_chud_pt * p, ecfp_chud_pt * r) {
+ int i;
+
+ PREFIX(copy) (r->x, p->x);
+ PREFIX(copy) (r->z, p->z);
+ PREFIX(copy) (r->z2, p->z2);
+ PREFIX(copy) (r->z3, p->z3);
+ for (i = 0; i < ECFP_NUMDOUBLES; i++) {
+ r->y[i] = -p->y[i];
+ }
+}
+
+/* Computes r = x + y. Does not tidy or reduce. Any combinations of r, x,
+ * y can point to the same data. Componentwise adds first ECFP_NUMDOUBLES
+ * doubles of x and y and stores the result in r. */
+void PREFIX(addShort) (double *r, const double *x, const double *y) {
+ int i;
+
+ for (i = 0; i < ECFP_NUMDOUBLES; i++) {
+ *r++ = *x++ + *y++;
+ }
+}
+
+/* Computes r = x + y. Does not tidy or reduce. Any combinations of r, x,
+ * y can point to the same data. Componentwise adds first
+ * 2*ECFP_NUMDOUBLES doubles of x and y and stores the result in r. */
+void PREFIX(addLong) (double *r, const double *x, const double *y) {
+ int i;
+
+ for (i = 0; i < 2 * ECFP_NUMDOUBLES; i++) {
+ *r++ = *x++ + *y++;
+ }
+}
+
+/* Computes r = x - y. Does not tidy or reduce. Any combinations of r, x,
+ * y can point to the same data. Componentwise subtracts first
+ * ECFP_NUMDOUBLES doubles of x and y and stores the result in r. */
+void PREFIX(subtractShort) (double *r, const double *x, const double *y) {
+ int i;
+
+ for (i = 0; i < ECFP_NUMDOUBLES; i++) {
+ *r++ = *x++ - *y++;
+ }
+}
+
+/* Computes r = x - y. Does not tidy or reduce. Any combinations of r, x,
+ * y can point to the same data. Componentwise subtracts first
+ * 2*ECFP_NUMDOUBLES doubles of x and y and stores the result in r. */
+void PREFIX(subtractLong) (double *r, const double *x, const double *y) {
+ int i;
+
+ for (i = 0; i < 2 * ECFP_NUMDOUBLES; i++) {
+ *r++ = *x++ - *y++;
+ }
+}
+
+/* Computes r = x*y. Both x and y should be tidied and reduced,
+ * r must be different (point to different memory) than x and y.
+ * Does not tidy or reduce. */
+void PREFIX(multiply)(double *r, const double *x, const double *y) {
+ int i, j;
+
+ for(j=0;j<ECFP_NUMDOUBLES-1;j++) {
+ r[j] = x[0] * y[j];
+ r[j+(ECFP_NUMDOUBLES-1)] = x[ECFP_NUMDOUBLES-1] * y[j];
+ }
+ r[ECFP_NUMDOUBLES-1] = x[0] * y[ECFP_NUMDOUBLES-1];
+ r[ECFP_NUMDOUBLES-1] += x[ECFP_NUMDOUBLES-1] * y[0];
+ r[2*ECFP_NUMDOUBLES-2] = x[ECFP_NUMDOUBLES-1] * y[ECFP_NUMDOUBLES-1];
+ r[2*ECFP_NUMDOUBLES-1] = 0;
+
+ for(i=1;i<ECFP_NUMDOUBLES-1;i++) {
+ for(j=0;j<ECFP_NUMDOUBLES;j++) {
+ r[i+j] += (x[i] * y[j]);
+ }
+ }
+}
+
+/* Computes the square of x and stores the result in r. x should be
+ * tidied & reduced, r will be neither tidied nor reduced.
+ * r should point to different memory than x */
+void PREFIX(square) (double *r, const double *x) {
+ PREFIX(multiply) (r, x, x);
+}
+
+/* Perform a point doubling in Jacobian coordinates. Input and output
+ * should be multi-precision floating point integers. */
+void PREFIX(pt_dbl_jac) (const ecfp_jac_pt * dp, ecfp_jac_pt * dr,
+ const EC_group_fp * group) {
+ double t0[2 * ECFP_NUMDOUBLES], t1[2 * ECFP_NUMDOUBLES],
+ M[2 * ECFP_NUMDOUBLES], S[2 * ECFP_NUMDOUBLES];
+
+ /* Check for point at infinity */
+ if (PREFIX(pt_is_inf_jac) (dp) == MP_YES) {
+ /* Set r = pt at infinity */
+ PREFIX(set_pt_inf_jac) (dr);
+ goto CLEANUP;
+ }
+
+ /* Perform typical point doubling operations */
+
+ /* TODO? is it worthwhile to do optimizations for when pz = 1? */
+
+ if (group->aIsM3) {
+ /* When a = -3, M = 3(px - pz^2)(px + pz^2) */
+ PREFIX(square) (t1, dp->z);
+ group->ecfp_reduce(t1, t1, group); /* 2^23 since the negative
+ * rounding buys another bit */
+ PREFIX(addShort) (t0, dp->x, t1); /* 2*2^23 */
+ PREFIX(subtractShort) (t1, dp->x, t1); /* 2 * 2^23 */
+ PREFIX(multiply) (M, t0, t1); /* 40 * 2^46 */
+ PREFIX(addLong) (t0, M, M); /* 80 * 2^46 */
+ PREFIX(addLong) (M, t0, M); /* 120 * 2^46 < 2^53 */
+ group->ecfp_reduce(M, M, group);
+ } else {
+ /* Generic case */
+ /* M = 3 (px^2) + a*(pz^4) */
+ PREFIX(square) (t0, dp->x);
+ PREFIX(addLong) (M, t0, t0);
+ PREFIX(addLong) (t0, t0, M); /* t0 = 3(px^2) */
+ PREFIX(square) (M, dp->z);
+ group->ecfp_reduce(M, M, group);
+ PREFIX(square) (t1, M);
+ group->ecfp_reduce(t1, t1, group);
+ PREFIX(multiply) (M, t1, group->curvea); /* M = a(pz^4) */
+ PREFIX(addLong) (M, M, t0);
+ group->ecfp_reduce(M, M, group);
+ }
+
+ /* rz = 2 * py * pz */
+ PREFIX(multiply) (t1, dp->y, dp->z);
+ PREFIX(addLong) (t1, t1, t1);
+ group->ecfp_reduce(dr->z, t1, group);
+
+ /* t0 = 2y^2 */
+ PREFIX(square) (t0, dp->y);
+ group->ecfp_reduce(t0, t0, group);
+ PREFIX(addShort) (t0, t0, t0);
+
+ /* S = 4 * px * py^2 = 2 * px * t0 */
+ PREFIX(multiply) (S, dp->x, t0);
+ PREFIX(addLong) (S, S, S);
+ group->ecfp_reduce(S, S, group);
+
+ /* rx = M^2 - 2 * S */
+ PREFIX(square) (t1, M);
+ PREFIX(subtractShort) (t1, t1, S);
+ PREFIX(subtractShort) (t1, t1, S);
+ group->ecfp_reduce(dr->x, t1, group);
+
+ /* ry = M * (S - rx) - 8 * py^4 */
+ PREFIX(square) (t1, t0); /* t1 = 4y^4 */
+ PREFIX(subtractShort) (S, S, dr->x);
+ PREFIX(multiply) (t0, M, S);
+ PREFIX(subtractLong) (t0, t0, t1);
+ PREFIX(subtractLong) (t0, t0, t1);
+ group->ecfp_reduce(dr->y, t0, group);
+
+ CLEANUP:
+ return;
+}
+
+/* Perform a point addition using coordinate system Jacobian + Affine ->
+ * Jacobian. Input and output should be multi-precision floating point
+ * integers. */
+void PREFIX(pt_add_jac_aff) (const ecfp_jac_pt * p, const ecfp_aff_pt * q,
+ ecfp_jac_pt * r, const EC_group_fp * group) {
+ /* Temporary storage */
+ double A[2 * ECFP_NUMDOUBLES], B[2 * ECFP_NUMDOUBLES],
+ C[2 * ECFP_NUMDOUBLES], C2[2 * ECFP_NUMDOUBLES],
+ D[2 * ECFP_NUMDOUBLES], C3[2 * ECFP_NUMDOUBLES];
+
+ /* Check for point at infinity for p or q */
+ if (PREFIX(pt_is_inf_aff) (q) == MP_YES) {
+ PREFIX(copy) (r->x, p->x);
+ PREFIX(copy) (r->y, p->y);
+ PREFIX(copy) (r->z, p->z);
+ goto CLEANUP;
+ } else if (PREFIX(pt_is_inf_jac) (p) == MP_YES) {
+ PREFIX(copy) (r->x, q->x);
+ PREFIX(copy) (r->y, q->y);
+ /* Since the affine point is not infinity, we can set r->z = 1 */
+ PREFIX(one) (r->z);
+ goto CLEANUP;
+ }
+
+ /* Calculates c = qx * pz^2 - px d = (qy * b - py) rx = d^2 - c^3 + 2
+ * (px * c^2) ry = d * (c-rx) - py*c^3 rz = c * pz */
+
+ /* A = pz^2, B = pz^3 */
+ PREFIX(square) (A, p->z);
+ group->ecfp_reduce(A, A, group);
+ PREFIX(multiply) (B, A, p->z);
+ group->ecfp_reduce(B, B, group);
+
+ /* C = qx * A - px */
+ PREFIX(multiply) (C, q->x, A);
+ PREFIX(subtractShort) (C, C, p->x);
+ group->ecfp_reduce(C, C, group);
+
+ /* D = qy * B - py */
+ PREFIX(multiply) (D, q->y, B);
+ PREFIX(subtractShort) (D, D, p->y);
+ group->ecfp_reduce(D, D, group);
+
+ /* C2 = C^2, C3 = C^3 */
+ PREFIX(square) (C2, C);
+ group->ecfp_reduce(C2, C2, group);
+ PREFIX(multiply) (C3, C2, C);
+ group->ecfp_reduce(C3, C3, group);
+
+ /* rz = A = pz * C */
+ PREFIX(multiply) (A, p->z, C);
+ group->ecfp_reduce(r->z, A, group);
+
+ /* C = px * C^2, untidied, unreduced */
+ PREFIX(multiply) (C, p->x, C2);
+
+ /* A = D^2, untidied, unreduced */
+ PREFIX(square) (A, D);
+
+ /* rx = B = A - C3 - C - C = D^2 - (C^3 + 2 * (px * C^2) */
+ PREFIX(subtractShort) (A, A, C3);
+ PREFIX(subtractLong) (A, A, C);
+ PREFIX(subtractLong) (A, A, C);
+ group->ecfp_reduce(r->x, A, group);
+
+ /* B = py * C3, untidied, unreduced */
+ PREFIX(multiply) (B, p->y, C3);
+
+ /* C = px * C^2 - rx */
+ PREFIX(subtractShort) (C, C, r->x);
+ group->ecfp_reduce(C, C, group);
+
+ /* ry = A = D * C - py * C^3 */
+ PREFIX(multiply) (A, D, C);
+ PREFIX(subtractLong) (A, A, B);
+ group->ecfp_reduce(r->y, A, group);
+
+ CLEANUP:
+ return;
+}
+
+/* Perform a point addition using Jacobian coordinate system. Input and
+ * output should be multi-precision floating point integers. */
+void PREFIX(pt_add_jac) (const ecfp_jac_pt * p, const ecfp_jac_pt * q,
+ ecfp_jac_pt * r, const EC_group_fp * group) {
+
+ /* Temporary Storage */
+ double t0[2 * ECFP_NUMDOUBLES], t1[2 * ECFP_NUMDOUBLES],
+ U[2 * ECFP_NUMDOUBLES], R[2 * ECFP_NUMDOUBLES],
+ S[2 * ECFP_NUMDOUBLES], H[2 * ECFP_NUMDOUBLES],
+ H3[2 * ECFP_NUMDOUBLES];
+
+ /* Check for point at infinity for p, if so set r = q */
+ if (PREFIX(pt_is_inf_jac) (p) == MP_YES) {
+ PREFIX(copy) (r->x, q->x);
+ PREFIX(copy) (r->y, q->y);
+ PREFIX(copy) (r->z, q->z);
+ goto CLEANUP;
+ }
+
+ /* Check for point at infinity for p, if so set r = q */
+ if (PREFIX(pt_is_inf_jac) (q) == MP_YES) {
+ PREFIX(copy) (r->x, p->x);
+ PREFIX(copy) (r->y, p->y);
+ PREFIX(copy) (r->z, p->z);
+ goto CLEANUP;
+ }
+
+ /* U = px * qz^2 , S = py * qz^3 */
+ PREFIX(square) (t0, q->z);
+ group->ecfp_reduce(t0, t0, group);
+ PREFIX(multiply) (U, p->x, t0);
+ group->ecfp_reduce(U, U, group);
+ PREFIX(multiply) (t1, t0, q->z);
+ group->ecfp_reduce(t1, t1, group);
+ PREFIX(multiply) (t0, p->y, t1);
+ group->ecfp_reduce(S, t0, group);
+
+ /* H = qx*(pz)^2 - U , R = (qy * pz^3 - S) */
+ PREFIX(square) (t0, p->z);
+ group->ecfp_reduce(t0, t0, group);
+ PREFIX(multiply) (H, q->x, t0);
+ PREFIX(subtractShort) (H, H, U);
+ group->ecfp_reduce(H, H, group);
+ PREFIX(multiply) (t1, t0, p->z); /* t1 = pz^3 */
+ group->ecfp_reduce(t1, t1, group);
+ PREFIX(multiply) (t0, t1, q->y); /* t0 = qy * pz^3 */
+ PREFIX(subtractShort) (t0, t0, S);
+ group->ecfp_reduce(R, t0, group);
+
+ /* U = U*H^2, H3 = H^3 */
+ PREFIX(square) (t0, H);
+ group->ecfp_reduce(t0, t0, group);
+ PREFIX(multiply) (t1, U, t0);
+ group->ecfp_reduce(U, t1, group);
+ PREFIX(multiply) (H3, t0, H);
+ group->ecfp_reduce(H3, H3, group);
+
+ /* rz = pz * qz * H */
+ PREFIX(multiply) (t0, q->z, H);
+ group->ecfp_reduce(t0, t0, group);
+ PREFIX(multiply) (t1, t0, p->z);
+ group->ecfp_reduce(r->z, t1, group);
+
+ /* rx = R^2 - H^3 - 2 * U */
+ PREFIX(square) (t0, R);
+ PREFIX(subtractShort) (t0, t0, H3);
+ PREFIX(subtractShort) (t0, t0, U);
+ PREFIX(subtractShort) (t0, t0, U);
+ group->ecfp_reduce(r->x, t0, group);
+
+ /* ry = R(U - rx) - S*H3 */
+ PREFIX(subtractShort) (t1, U, r->x);
+ PREFIX(multiply) (t0, t1, R);
+ PREFIX(multiply) (t1, S, H3);
+ PREFIX(subtractLong) (t1, t0, t1);
+ group->ecfp_reduce(r->y, t1, group);
+
+ CLEANUP:
+ return;
+}
+
+/* Perform a point doubling in Modified Jacobian coordinates. Input and
+ * output should be multi-precision floating point integers. */
+void PREFIX(pt_dbl_jm) (const ecfp_jm_pt * p, ecfp_jm_pt * r,
+ const EC_group_fp * group) {
+
+ /* Temporary storage */
+ double t0[2 * ECFP_NUMDOUBLES], t1[2 * ECFP_NUMDOUBLES],
+ M[2 * ECFP_NUMDOUBLES], S[2 * ECFP_NUMDOUBLES],
+ U[2 * ECFP_NUMDOUBLES], T[2 * ECFP_NUMDOUBLES];
+
+ /* Check for point at infinity */
+ if (PREFIX(pt_is_inf_jm) (p) == MP_YES) {
+ /* Set r = pt at infinity by setting rz = 0 */
+ PREFIX(set_pt_inf_jm) (r);
+ goto CLEANUP;
+ }
+
+ /* M = 3 (px^2) + a*(pz^4) */
+ PREFIX(square) (t0, p->x);
+ PREFIX(addLong) (M, t0, t0);
+ PREFIX(addLong) (t0, t0, M); /* t0 = 3(px^2) */
+ PREFIX(addShort) (t0, t0, p->az4);
+ group->ecfp_reduce(M, t0, group);
+
+ /* rz = 2 * py * pz */
+ PREFIX(multiply) (t1, p->y, p->z);
+ PREFIX(addLong) (t1, t1, t1);
+ group->ecfp_reduce(r->z, t1, group);
+
+ /* t0 = 2y^2, U = 8y^4 */
+ PREFIX(square) (t0, p->y);
+ group->ecfp_reduce(t0, t0, group);
+ PREFIX(addShort) (t0, t0, t0);
+ PREFIX(square) (U, t0);
+ group->ecfp_reduce(U, U, group);
+ PREFIX(addShort) (U, U, U);
+
+ /* S = 4 * px * py^2 = 2 * px * t0 */
+ PREFIX(multiply) (S, p->x, t0);
+ group->ecfp_reduce(S, S, group);
+ PREFIX(addShort) (S, S, S);
+
+ /* rx = M^2 - 2S */
+ PREFIX(square) (T, M);
+ PREFIX(subtractShort) (T, T, S);
+ PREFIX(subtractShort) (T, T, S);
+ group->ecfp_reduce(r->x, T, group);
+
+ /* ry = M * (S - rx) - U */
+ PREFIX(subtractShort) (S, S, r->x);
+ PREFIX(multiply) (t0, M, S);
+ PREFIX(subtractShort) (t0, t0, U);
+ group->ecfp_reduce(r->y, t0, group);
+
+ /* ra*z^4 = 2*U*(apz4) */
+ PREFIX(multiply) (t1, U, p->az4);
+ PREFIX(addLong) (t1, t1, t1);
+ group->ecfp_reduce(r->az4, t1, group);
+
+ CLEANUP:
+ return;
+}
+
+/* Perform a point doubling using coordinates Affine -> Chudnovsky
+ * Jacobian. Input and output should be multi-precision floating point
+ * integers. */
+void PREFIX(pt_dbl_aff2chud) (const ecfp_aff_pt * p, ecfp_chud_pt * r,
+ const EC_group_fp * group) {
+ double t0[2 * ECFP_NUMDOUBLES], t1[2 * ECFP_NUMDOUBLES],
+ M[2 * ECFP_NUMDOUBLES], twoY2[2 * ECFP_NUMDOUBLES],
+ S[2 * ECFP_NUMDOUBLES];
+
+ /* Check for point at infinity for p, if so set r = O */
+ if (PREFIX(pt_is_inf_aff) (p) == MP_YES) {
+ PREFIX(set_pt_inf_chud) (r);
+ goto CLEANUP;
+ }
+
+ /* M = 3(px)^2 + a */
+ PREFIX(square) (t0, p->x);
+ PREFIX(addLong) (t1, t0, t0);
+ PREFIX(addLong) (t1, t1, t0);
+ PREFIX(addShort) (t1, t1, group->curvea);
+ group->ecfp_reduce(M, t1, group);
+
+ /* twoY2 = 2*(py)^2, S = 4(px)(py)^2 */
+ PREFIX(square) (twoY2, p->y);
+ PREFIX(addLong) (twoY2, twoY2, twoY2);
+ group->ecfp_reduce(twoY2, twoY2, group);
+ PREFIX(multiply) (S, p->x, twoY2);
+ PREFIX(addLong) (S, S, S);
+ group->ecfp_reduce(S, S, group);
+
+ /* rx = M^2 - 2S */
+ PREFIX(square) (t0, M);
+ PREFIX(subtractShort) (t0, t0, S);
+ PREFIX(subtractShort) (t0, t0, S);
+ group->ecfp_reduce(r->x, t0, group);
+
+ /* ry = M(S-rx) - 8y^4 */
+ PREFIX(subtractShort) (t0, S, r->x);
+ PREFIX(multiply) (t1, t0, M);
+ PREFIX(square) (t0, twoY2);
+ PREFIX(subtractLong) (t1, t1, t0);
+ PREFIX(subtractLong) (t1, t1, t0);
+ group->ecfp_reduce(r->y, t1, group);
+
+ /* rz = 2py */
+ PREFIX(addShort) (r->z, p->y, p->y);
+
+ /* rz2 = rz^2 */
+ PREFIX(square) (t0, r->z);
+ group->ecfp_reduce(r->z2, t0, group);
+
+ /* rz3 = rz^3 */
+ PREFIX(multiply) (t0, r->z, r->z2);
+ group->ecfp_reduce(r->z3, t0, group);
+
+ CLEANUP:
+ return;
+}
+
+/* Perform a point addition using coordinates: Modified Jacobian +
+ * Chudnovsky Jacobian -> Modified Jacobian. Input and output should be
+ * multi-precision floating point integers. */
+void PREFIX(pt_add_jm_chud) (ecfp_jm_pt * p, ecfp_chud_pt * q,
+ ecfp_jm_pt * r, const EC_group_fp * group) {
+
+ double t0[2 * ECFP_NUMDOUBLES], t1[2 * ECFP_NUMDOUBLES],
+ U[2 * ECFP_NUMDOUBLES], R[2 * ECFP_NUMDOUBLES],
+ S[2 * ECFP_NUMDOUBLES], H[2 * ECFP_NUMDOUBLES],
+ H3[2 * ECFP_NUMDOUBLES], pz2[2 * ECFP_NUMDOUBLES];
+
+ /* Check for point at infinity for p, if so set r = q need to convert
+ * from Chudnovsky form to Modified Jacobian form */
+ if (PREFIX(pt_is_inf_jm) (p) == MP_YES) {
+ PREFIX(copy) (r->x, q->x);
+ PREFIX(copy) (r->y, q->y);
+ PREFIX(copy) (r->z, q->z);
+ PREFIX(square) (t0, q->z2);
+ group->ecfp_reduce(t0, t0, group);
+ PREFIX(multiply) (t1, t0, group->curvea);
+ group->ecfp_reduce(r->az4, t1, group);
+ goto CLEANUP;
+ }
+ /* Check for point at infinity for q, if so set r = p */
+ if (PREFIX(pt_is_inf_chud) (q) == MP_YES) {
+ PREFIX(copy) (r->x, p->x);
+ PREFIX(copy) (r->y, p->y);
+ PREFIX(copy) (r->z, p->z);
+ PREFIX(copy) (r->az4, p->az4);
+ goto CLEANUP;
+ }
+
+ /* U = px * qz^2 */
+ PREFIX(multiply) (U, p->x, q->z2);
+ group->ecfp_reduce(U, U, group);
+
+ /* H = qx*(pz)^2 - U */
+ PREFIX(square) (t0, p->z);
+ group->ecfp_reduce(pz2, t0, group);
+ PREFIX(multiply) (H, pz2, q->x);
+ group->ecfp_reduce(H, H, group);
+ PREFIX(subtractShort) (H, H, U);
+
+ /* U = U*H^2, H3 = H^3 */
+ PREFIX(square) (t0, H);
+ group->ecfp_reduce(t0, t0, group);
+ PREFIX(multiply) (t1, U, t0);
+ group->ecfp_reduce(U, t1, group);
+ PREFIX(multiply) (H3, t0, H);
+ group->ecfp_reduce(H3, H3, group);
+
+ /* S = py * qz^3 */
+ PREFIX(multiply) (S, p->y, q->z3);
+ group->ecfp_reduce(S, S, group);
+
+ /* R = (qy * z1^3 - s) */
+ PREFIX(multiply) (t0, pz2, p->z);
+ group->ecfp_reduce(t0, t0, group);
+ PREFIX(multiply) (R, t0, q->y);
+ PREFIX(subtractShort) (R, R, S);
+ group->ecfp_reduce(R, R, group);
+
+ /* rz = pz * qz * H */
+ PREFIX(multiply) (t1, q->z, H);
+ group->ecfp_reduce(t1, t1, group);
+ PREFIX(multiply) (t0, p->z, t1);
+ group->ecfp_reduce(r->z, t0, group);
+
+ /* rx = R^2 - H^3 - 2 * U */
+ PREFIX(square) (t0, R);
+ PREFIX(subtractShort) (t0, t0, H3);
+ PREFIX(subtractShort) (t0, t0, U);
+ PREFIX(subtractShort) (t0, t0, U);
+ group->ecfp_reduce(r->x, t0, group);
+
+ /* ry = R(U - rx) - S*H3 */
+ PREFIX(subtractShort) (t1, U, r->x);
+ PREFIX(multiply) (t0, t1, R);
+ PREFIX(multiply) (t1, S, H3);
+ PREFIX(subtractLong) (t1, t0, t1);
+ group->ecfp_reduce(r->y, t1, group);
+
+ if (group->aIsM3) { /* a == -3 */
+ /* a(rz^4) = -3 * ((rz^2)^2) */
+ PREFIX(square) (t0, r->z);
+ group->ecfp_reduce(t0, t0, group);
+ PREFIX(square) (t1, t0);
+ PREFIX(addLong) (t0, t1, t1);
+ PREFIX(addLong) (t0, t0, t1);
+ PREFIX(negLong) (t0, t0);
+ group->ecfp_reduce(r->az4, t0, group);
+ } else { /* Generic case */
+ /* a(rz^4) = a * ((rz^2)^2) */
+ PREFIX(square) (t0, r->z);
+ group->ecfp_reduce(t0, t0, group);
+ PREFIX(square) (t1, t0);
+ group->ecfp_reduce(t1, t1, group);
+ PREFIX(multiply) (t0, group->curvea, t1);
+ group->ecfp_reduce(r->az4, t0, group);
+ }
+ CLEANUP:
+ return;
+}
+
+/* Perform a point addition using Chudnovsky Jacobian coordinates. Input
+ * and output should be multi-precision floating point integers. */
+void PREFIX(pt_add_chud) (const ecfp_chud_pt * p, const ecfp_chud_pt * q,
+ ecfp_chud_pt * r, const EC_group_fp * group) {
+
+ /* Temporary Storage */
+ double t0[2 * ECFP_NUMDOUBLES], t1[2 * ECFP_NUMDOUBLES],
+ U[2 * ECFP_NUMDOUBLES], R[2 * ECFP_NUMDOUBLES],
+ S[2 * ECFP_NUMDOUBLES], H[2 * ECFP_NUMDOUBLES],
+ H3[2 * ECFP_NUMDOUBLES];
+
+ /* Check for point at infinity for p, if so set r = q */
+ if (PREFIX(pt_is_inf_chud) (p) == MP_YES) {
+ PREFIX(copy) (r->x, q->x);
+ PREFIX(copy) (r->y, q->y);
+ PREFIX(copy) (r->z, q->z);
+ PREFIX(copy) (r->z2, q->z2);
+ PREFIX(copy) (r->z3, q->z3);
+ goto CLEANUP;
+ }
+
+ /* Check for point at infinity for p, if so set r = q */
+ if (PREFIX(pt_is_inf_chud) (q) == MP_YES) {
+ PREFIX(copy) (r->x, p->x);
+ PREFIX(copy) (r->y, p->y);
+ PREFIX(copy) (r->z, p->z);
+ PREFIX(copy) (r->z2, p->z2);
+ PREFIX(copy) (r->z3, p->z3);
+ goto CLEANUP;
+ }
+
+ /* U = px * qz^2 */
+ PREFIX(multiply) (U, p->x, q->z2);
+ group->ecfp_reduce(U, U, group);
+
+ /* H = qx*(pz)^2 - U */
+ PREFIX(multiply) (H, q->x, p->z2);
+ PREFIX(subtractShort) (H, H, U);
+ group->ecfp_reduce(H, H, group);
+
+ /* U = U*H^2, H3 = H^3 */
+ PREFIX(square) (t0, H);
+ group->ecfp_reduce(t0, t0, group);
+ PREFIX(multiply) (t1, U, t0);
+ group->ecfp_reduce(U, t1, group);
+ PREFIX(multiply) (H3, t0, H);
+ group->ecfp_reduce(H3, H3, group);
+
+ /* S = py * qz^3 */
+ PREFIX(multiply) (S, p->y, q->z3);
+ group->ecfp_reduce(S, S, group);
+
+ /* rz = pz * qz * H */
+ PREFIX(multiply) (t0, q->z, H);
+ group->ecfp_reduce(t0, t0, group);
+ PREFIX(multiply) (t1, t0, p->z);
+ group->ecfp_reduce(r->z, t1, group);
+
+ /* R = (qy * z1^3 - s) */
+ PREFIX(multiply) (t0, q->y, p->z3);
+ PREFIX(subtractShort) (t0, t0, S);
+ group->ecfp_reduce(R, t0, group);
+
+ /* rx = R^2 - H^3 - 2 * U */
+ PREFIX(square) (t0, R);
+ PREFIX(subtractShort) (t0, t0, H3);
+ PREFIX(subtractShort) (t0, t0, U);
+ PREFIX(subtractShort) (t0, t0, U);
+ group->ecfp_reduce(r->x, t0, group);
+
+ /* ry = R(U - rx) - S*H3 */
+ PREFIX(subtractShort) (t1, U, r->x);
+ PREFIX(multiply) (t0, t1, R);
+ PREFIX(multiply) (t1, S, H3);
+ PREFIX(subtractLong) (t1, t0, t1);
+ group->ecfp_reduce(r->y, t1, group);
+
+ /* rz2 = rz^2 */
+ PREFIX(square) (t0, r->z);
+ group->ecfp_reduce(r->z2, t0, group);
+
+ /* rz3 = rz^3 */
+ PREFIX(multiply) (t0, r->z, r->z2);
+ group->ecfp_reduce(r->z3, t0, group);
+
+ CLEANUP:
+ return;
+}
+
+/* Expects out to be an array of size 16 of Chudnovsky Jacobian points.
+ * Fills in Chudnovsky Jacobian form (x, y, z, z^2, z^3), for -15P, -13P,
+ * -11P, -9P, -7P, -5P, -3P, -P, P, 3P, 5P, 7P, 9P, 11P, 13P, 15P */
+void PREFIX(precompute_chud) (ecfp_chud_pt * out, const ecfp_aff_pt * p,
+ const EC_group_fp * group) {
+
+ ecfp_chud_pt p2;
+
+ /* Set out[8] = P */
+ PREFIX(copy) (out[8].x, p->x);
+ PREFIX(copy) (out[8].y, p->y);
+ PREFIX(one) (out[8].z);
+ PREFIX(one) (out[8].z2);
+ PREFIX(one) (out[8].z3);
+
+ /* Set p2 = 2P */
+ PREFIX(pt_dbl_aff2chud) (p, &p2, group);
+
+ /* Set 3P, 5P, ..., 15P */
+ PREFIX(pt_add_chud) (&out[8], &p2, &out[9], group);
+ PREFIX(pt_add_chud) (&out[9], &p2, &out[10], group);
+ PREFIX(pt_add_chud) (&out[10], &p2, &out[11], group);
+ PREFIX(pt_add_chud) (&out[11], &p2, &out[12], group);
+ PREFIX(pt_add_chud) (&out[12], &p2, &out[13], group);
+ PREFIX(pt_add_chud) (&out[13], &p2, &out[14], group);
+ PREFIX(pt_add_chud) (&out[14], &p2, &out[15], group);
+
+ /* Set -15P, -13P, ..., -P */
+ PREFIX(pt_neg_chud) (&out[8], &out[7]);
+ PREFIX(pt_neg_chud) (&out[9], &out[6]);
+ PREFIX(pt_neg_chud) (&out[10], &out[5]);
+ PREFIX(pt_neg_chud) (&out[11], &out[4]);
+ PREFIX(pt_neg_chud) (&out[12], &out[3]);
+ PREFIX(pt_neg_chud) (&out[13], &out[2]);
+ PREFIX(pt_neg_chud) (&out[14], &out[1]);
+ PREFIX(pt_neg_chud) (&out[15], &out[0]);
+}
+
+/* Expects out to be an array of size 16 of Jacobian points. Fills in
+ * Jacobian form (x, y, z), for O, P, 2P, ... 15P */
+void PREFIX(precompute_jac) (ecfp_jac_pt * precomp, const ecfp_aff_pt * p,
+ const EC_group_fp * group) {
+ int i;
+
+ /* fill precomputation table */
+ /* set precomp[0] */
+ PREFIX(set_pt_inf_jac) (&precomp[0]);
+ /* set precomp[1] */
+ PREFIX(copy) (precomp[1].x, p->x);
+ PREFIX(copy) (precomp[1].y, p->y);
+ if (PREFIX(pt_is_inf_aff) (p) == MP_YES) {
+ PREFIX(zero) (precomp[1].z);
+ } else {
+ PREFIX(one) (precomp[1].z);
+ }
+ /* set precomp[2] */
+ group->pt_dbl_jac(&precomp[1], &precomp[2], group);
+
+ /* set rest of precomp */
+ for (i = 3; i < 16; i++) {
+ group->pt_add_jac_aff(&precomp[i - 1], p, &precomp[i], group);
+ }
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_jac.c b/mozilla/security/nss/lib/freebl/ecl/ecp_jac.c
new file mode 100644
index 0000000..2659dbb
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_jac.c
@@ -0,0 +1,553 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ecp.h"
+#include "mplogic.h"
+#include <stdlib.h>
+#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));
+ MP_CHECKOK(mp_init(&z2));
+ MP_CHECKOK(mp_init(&z3));
+
+ /* 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));
+ MP_CHECKOK(mp_init(&B));
+ MP_CHECKOK(mp_init(&C));
+ MP_CHECKOK(mp_init(&D));
+ MP_CHECKOK(mp_init(&C2));
+ MP_CHECKOK(mp_init(&C3));
+
+ /* 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));
+ MP_CHECKOK(mp_init(&t1));
+ MP_CHECKOK(mp_init(&M));
+ MP_CHECKOK(mp_init(&S));
+
+ 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) == 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]));
+ MP_CHECKOK(mp_init(&precomp[i][j][1]));
+ }
+ }
+
+ /* 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));
+ MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz));
+
+ for (i = d - 1; i >= 0; i--) {
+ ai = MP_GET_BIT(a, 2 * i + 1);
+ ai <<= 1;
+ ai |= MP_GET_BIT(a, 2 * i);
+ bi = MP_GET_BIT(b, 2 * i + 1);
+ bi <<= 1;
+ bi |= MP_GET_BIT(b, 2 * i);
+ /* R = 2^2 * R */
+ MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
+ MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
+ /* R = R + (ai * A + bi * B) */
+ MP_CHECKOK(ec_GFp_pt_add_jac_aff
+ (rx, ry, &rz, &precomp[ai][bi][0], &precomp[ai][bi][1],
+ rx, ry, &rz, group));
+ }
+
+ MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group));
+
+ if (group->meth->field_dec) {
+ MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth));
+ MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth));
+ }
+
+ CLEANUP:
+ mp_clear(&rz);
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ mp_clear(&precomp[i][j][0]);
+ mp_clear(&precomp[i][j][1]);
+ }
+ }
+ return res;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_jm.c b/mozilla/security/nss/lib/freebl/ecl/ecp_jm.c
new file mode 100644
index 0000000..f015a61
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_jm.c
@@ -0,0 +1,323 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ecp.h"
+#include "ecl-priv.h"
+#include "mplogic.h"
+#include <stdlib.h>
+
+#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));
+ MP_CHECKOK(mp_init(&tpy));;
+ MP_CHECKOK(mp_init(&rz));
+ MP_CHECKOK(mp_init(&raz4));
+
+ for (i = 0; i < 16; i++) {
+ MP_CHECKOK(mp_init(&precomp[i][0]));
+ MP_CHECKOK(mp_init(&precomp[i][1]));
+ }
+ for (i = 0; i < MAX_SCRATCH; i++) {
+ MP_CHECKOK(mp_init(&scratch[i]));
+ }
+
+ /* 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 */
+ naf = (signed char *) malloc(sizeof(signed char) * (orderBitSize + 1));
+ if (naf == NULL) {
+ res = MP_MEM;
+ goto CLEANUP;
+ }
+
+ /* 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);
+ free(naf);
+ return res;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_mont.c b/mozilla/security/nss/lib/freebl/ecl/ecp_mont.c
new file mode 100644
index 0000000..c8829b6
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/ecp_mont.c
@@ -0,0 +1,192 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* 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"
+#include <stdlib.h>
+#include <stdio.h>
+
+/* 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;
+
+ mmm = (mp_mont_modulus *) malloc(sizeof(mp_mont_modulus));
+ 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));
+ 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) {
+ free(meth->extra1);
+ meth->extra1 = NULL;
+ }
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/tests/ec2_test.c b/mozilla/security/nss/lib/freebl/ecl/tests/ec2_test.c
new file mode 100644
index 0000000..cf65402
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/tests/ec2_test.c
@@ -0,0 +1,516 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "mpi.h"
+#include "mplogic.h"
+#include "mpprime.h"
+#include "mp_gf2m.h"
+#include "ecl.h"
+#include "ecl-curve.h"
+#include "ec2.h"
+#include <stdio.h>
+#include <strings.h>
+#include <assert.h>
+
+#include <time.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+/* Time k repetitions of operation op. */
+#define M_TimeOperation(op, k) { \
+ double dStart, dNow, dUserTime; \
+ struct rusage ru; \
+ int i; \
+ getrusage(RUSAGE_SELF, &ru); \
+ dStart = (double)ru.ru_utime.tv_sec+(double)ru.ru_utime.tv_usec*0.000001; \
+ for (i = 0; i < k; i++) { \
+ { op; } \
+ }; \
+ getrusage(RUSAGE_SELF, &ru); \
+ dNow = (double)ru.ru_utime.tv_sec+(double)ru.ru_utime.tv_usec*0.000001; \
+ dUserTime = dNow-dStart; \
+ if (dUserTime) printf(" %-45s k: %6i, t: %6.2f sec\n", #op, k, dUserTime); \
+}
+
+/* Test curve using generic field arithmetic. */
+#define ECTEST_GENERIC_GF2M(name_c, name) \
+ printf("Testing %s using generic implementation...\n", name_c); \
+ params = EC_GetNamedCurveParams(name); \
+ if (params == NULL) { \
+ printf(" Error: could not construct params.\n"); \
+ res = MP_NO; \
+ goto CLEANUP; \
+ } \
+ ECGroup_free(group); \
+ group = ECGroup_fromHex(params); \
+ if (group == NULL) { \
+ printf(" Error: could not construct group.\n"); \
+ res = MP_NO; \
+ goto CLEANUP; \
+ } \
+ MP_CHECKOK( ectest_curve_GF2m(group, ectestPrint, ectestTime, 1) ); \
+ printf("... okay.\n");
+
+/* Test curve using specific field arithmetic. */
+#define ECTEST_NAMED_GF2M(name_c, name) \
+ printf("Testing %s using specific implementation...\n", name_c); \
+ ECGroup_free(group); \
+ group = ECGroup_fromName(name); \
+ if (group == NULL) { \
+ printf(" Warning: could not construct group.\n"); \
+ printf("... failed; continuing with remaining tests.\n"); \
+ } else { \
+ MP_CHECKOK( ectest_curve_GF2m(group, ectestPrint, ectestTime, 0) ); \
+ printf("... okay.\n"); \
+ }
+
+/* Performs basic tests of elliptic curve cryptography over binary
+ * polynomial fields. If tests fail, then it prints an error message,
+ * aborts, and returns an error code. Otherwise, returns 0. */
+int
+ectest_curve_GF2m(ECGroup *group, int ectestPrint, int ectestTime,
+ int generic)
+{
+
+ mp_int one, order_1, gx, gy, rx, ry, n;
+ int size;
+ mp_err res;
+ char s[1000];
+
+ /* initialize values */
+ MP_CHECKOK(mp_init(&one));
+ MP_CHECKOK(mp_init(&order_1));
+ MP_CHECKOK(mp_init(&gx));
+ MP_CHECKOK(mp_init(&gy));
+ MP_CHECKOK(mp_init(&rx));
+ MP_CHECKOK(mp_init(&ry));
+ MP_CHECKOK(mp_init(&n));
+
+ MP_CHECKOK(mp_set_int(&one, 1));
+ MP_CHECKOK(mp_sub(&group->order, &one, &order_1));
+
+ /* encode base point */
+ if (group->meth->field_dec) {
+ MP_CHECKOK(group->meth->field_dec(&group->genx, &gx, group->meth));
+ MP_CHECKOK(group->meth->field_dec(&group->geny, &gy, group->meth));
+ } else {
+ MP_CHECKOK(mp_copy(&group->genx, &gx));
+ MP_CHECKOK(mp_copy(&group->geny, &gy));
+ }
+
+ if (ectestPrint) {
+ /* output base point */
+ printf(" base point P:\n");
+ MP_CHECKOK(mp_toradix(&gx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&gy, s, 16));
+ printf(" %s\n", s);
+ if (group->meth->field_enc) {
+ printf(" base point P (encoded):\n");
+ MP_CHECKOK(mp_toradix(&group->genx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&group->geny, s, 16));
+ printf(" %s\n", s);
+ }
+ }
+
+#ifdef ECL_ENABLE_GF2M_PT_MUL_AFF
+ /* multiply base point by order - 1 and check for negative of base
+ * point */
+ MP_CHECKOK(ec_GF2m_pt_mul_aff
+ (&order_1, &group->genx, &group->geny, &rx, &ry, group));
+ if (ectestPrint) {
+ printf(" (order-1)*P (affine):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ MP_CHECKOK(group->meth->field_add(&ry, &rx, &ry, group->meth));
+ if ((mp_cmp(&rx, &group->genx) != 0)
+ || (mp_cmp(&ry, &group->geny) != 0)) {
+ printf(" Error: invalid result (expected (- base point)).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+#endif
+
+ /* multiply base point by order - 1 and check for negative of base
+ * point */
+ MP_CHECKOK(ec_GF2m_pt_mul_mont
+ (&order_1, &group->genx, &group->geny, &rx, &ry, group));
+ if (ectestPrint) {
+ printf(" (order-1)*P (montgomery):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ MP_CHECKOK(group->meth->field_add(&ry, &rx, &ry, group->meth));
+ if ((mp_cmp(&rx, &group->genx) != 0)
+ || (mp_cmp(&ry, &group->geny) != 0)) {
+ printf(" Error: invalid result (expected (- base point)).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+#ifdef ECL_ENABLE_GF2M_PROJ
+ /* multiply base point by order - 1 and check for negative of base
+ * point */
+ MP_CHECKOK(ec_GF2m_pt_mul_proj
+ (&order_1, &group->genx, &group->geny, &rx, &ry, group));
+ if (ectestPrint) {
+ printf(" (order-1)*P (projective):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ MP_CHECKOK(group->meth->field_add(&ry, &rx, &ry, group->meth));
+ if ((mp_cmp(&rx, &group->genx) != 0)
+ || (mp_cmp(&ry, &group->geny) != 0)) {
+ printf(" Error: invalid result (expected (- base point)).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+#endif
+
+ /* multiply base point by order - 1 and check for negative of base
+ * point */
+ MP_CHECKOK(ECPoint_mul(group, &order_1, NULL, NULL, &rx, &ry));
+ if (ectestPrint) {
+ printf(" (order-1)*P (ECPoint_mul):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ MP_CHECKOK(ec_GF2m_add(&ry, &rx, &ry, group->meth));
+ if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) {
+ printf(" Error: invalid result (expected (- base point)).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ /* multiply base point by order - 1 and check for negative of base
+ * point */
+ MP_CHECKOK(ECPoint_mul(group, &order_1, &gx, &gy, &rx, &ry));
+ if (ectestPrint) {
+ printf(" (order-1)*P (ECPoint_mul):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ MP_CHECKOK(ec_GF2m_add(&ry, &rx, &ry, group->meth));
+ if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) {
+ printf(" Error: invalid result (expected (- base point)).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+#ifdef ECL_ENABLE_GF2M_PT_MUL_AFF
+ /* multiply base point by order and check for point at infinity */
+ MP_CHECKOK(ec_GF2m_pt_mul_aff
+ (&group->order, &group->genx, &group->geny, &rx, &ry,
+ group));
+ if (ectestPrint) {
+ printf(" (order)*P (affine):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ if (ec_GF2m_pt_is_inf_aff(&rx, &ry) != MP_YES) {
+ printf(" Error: invalid result (expected point at infinity).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+#endif
+
+ /* multiply base point by order and check for point at infinity */
+ MP_CHECKOK(ec_GF2m_pt_mul_mont
+ (&group->order, &group->genx, &group->geny, &rx, &ry,
+ group));
+ if (ectestPrint) {
+ printf(" (order)*P (montgomery):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ if (ec_GF2m_pt_is_inf_aff(&rx, &ry) != MP_YES) {
+ printf(" Error: invalid result (expected point at infinity).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+#ifdef ECL_ENABLE_GF2M_PROJ
+ /* multiply base point by order and check for point at infinity */
+ MP_CHECKOK(ec_GF2m_pt_mul_proj
+ (&group->order, &group->genx, &group->geny, &rx, &ry,
+ group));
+ if (ectestPrint) {
+ printf(" (order)*P (projective):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ if (ec_GF2m_pt_is_inf_aff(&rx, &ry) != MP_YES) {
+ printf(" Error: invalid result (expected point at infinity).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+#endif
+
+ /* multiply base point by order and check for point at infinity */
+ MP_CHECKOK(ECPoint_mul(group, &group->order, NULL, NULL, &rx, &ry));
+ if (ectestPrint) {
+ printf(" (order)*P (ECPoint_mul):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ if (ec_GF2m_pt_is_inf_aff(&rx, &ry) != MP_YES) {
+ printf(" Error: invalid result (expected point at infinity).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ /* multiply base point by order and check for point at infinity */
+ MP_CHECKOK(ECPoint_mul(group, &group->order, &gx, &gy, &rx, &ry));
+ if (ectestPrint) {
+ printf(" (order)*P (ECPoint_mul):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ if (ec_GF2m_pt_is_inf_aff(&rx, &ry) != MP_YES) {
+ printf(" Error: invalid result (expected point at infinity).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ /* check that (order-1)P + (order-1)P + P == (order-1)P */
+ MP_CHECKOK(ECPoints_mul
+ (group, &order_1, &order_1, &gx, &gy, &rx, &ry));
+ MP_CHECKOK(ECPoints_mul(group, &one, &one, &rx, &ry, &rx, &ry));
+ if (ectestPrint) {
+ printf
+ (" (order-1)*P + (order-1)*P + P == (order-1)*P (ECPoints_mul):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ MP_CHECKOK(ec_GF2m_add(&ry, &rx, &ry, group->meth));
+ if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) {
+ printf(" Error: invalid result (expected (- base point)).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ /* test validate_point function */
+ if (ECPoint_validate(group, &gx, &gy) != MP_YES) {
+ printf(" Error: validate point on base point failed.\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+ MP_CHECKOK(mp_add_d(&gy, 1, &ry));
+ if (ECPoint_validate(group, &gx, &ry) != MP_NO) {
+ printf(" Error: validate point on invalid point passed.\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ if (ectestTime) {
+ /* compute random scalar */
+ size = mpl_significant_bits(&group->meth->irr);
+ if (size < MP_OKAY) {
+ goto CLEANUP;
+ }
+ MP_CHECKOK(mpp_random_size(&n, (size + ECL_BITS - 1) / ECL_BITS));
+ MP_CHECKOK(group->meth->field_mod(&n, &n, group->meth));
+ /* timed test */
+ if (generic) {
+#ifdef ECL_ENABLE_GF2M_PT_MUL_AFF
+ M_TimeOperation(MP_CHECKOK
+ (ec_GF2m_pt_mul_aff
+ (&n, &group->genx, &group->geny, &rx, &ry,
+ group)), 100);
+#endif
+ M_TimeOperation(MP_CHECKOK
+ (ECPoint_mul(group, &n, NULL, NULL, &rx, &ry)),
+ 100);
+ M_TimeOperation(MP_CHECKOK
+ (ECPoints_mul
+ (group, &n, &n, &gx, &gy, &rx, &ry)), 100);
+ } else {
+ M_TimeOperation(MP_CHECKOK
+ (ECPoint_mul(group, &n, NULL, NULL, &rx, &ry)),
+ 100);
+ M_TimeOperation(MP_CHECKOK
+ (ECPoint_mul(group, &n, &gx, &gy, &rx, &ry)),
+ 100);
+ M_TimeOperation(MP_CHECKOK
+ (ECPoints_mul
+ (group, &n, &n, &gx, &gy, &rx, &ry)), 100);
+ }
+ }
+
+ CLEANUP:
+ mp_clear(&one);
+ mp_clear(&order_1);
+ mp_clear(&gx);
+ mp_clear(&gy);
+ mp_clear(&rx);
+ mp_clear(&ry);
+ mp_clear(&n);
+ if (res != MP_OKAY) {
+ printf(" Error: exiting with error value %i\n", res);
+ }
+ return res;
+}
+
+/* Prints help information. */
+void
+printUsage()
+{
+ printf("Usage: ecp_test [--print] [--time]\n");
+ printf
+ (" --print Print out results of each point arithmetic test.\n");
+ printf
+ (" --time Benchmark point operations and print results.\n");
+}
+
+/* Performs tests of elliptic curve cryptography over binary polynomial
+ * fields. If tests fail, then it prints an error message, aborts, and
+ * returns an error code. Otherwise, returns 0. */
+int
+main(int argv, char **argc)
+{
+
+ int ectestTime = 0;
+ int ectestPrint = 0;
+ int i;
+ ECGroup *group = NULL;
+ ECCurveParams *params = NULL;
+ mp_err res;
+
+ /* read command-line arguments */
+ for (i = 1; i < argv; i++) {
+ if ((strcasecmp(argc[i], "time") == 0)
+ || (strcasecmp(argc[i], "-time") == 0)
+ || (strcasecmp(argc[i], "--time") == 0)) {
+ ectestTime = 1;
+ } else if ((strcasecmp(argc[i], "print") == 0)
+ || (strcasecmp(argc[i], "-print") == 0)
+ || (strcasecmp(argc[i], "--print") == 0)) {
+ ectestPrint = 1;
+ } else {
+ printUsage();
+ return 0;
+ }
+ }
+
+ /* generic arithmetic tests */
+ ECTEST_GENERIC_GF2M("SECT-131R1", ECCurve_SECG_CHAR2_131R1);
+
+ /* specific arithmetic tests */
+ ECTEST_NAMED_GF2M("NIST-K163", ECCurve_NIST_K163);
+ ECTEST_NAMED_GF2M("NIST-B163", ECCurve_NIST_B163);
+ ECTEST_NAMED_GF2M("NIST-K233", ECCurve_NIST_K233);
+ ECTEST_NAMED_GF2M("NIST-B233", ECCurve_NIST_B233);
+ ECTEST_NAMED_GF2M("NIST-K283", ECCurve_NIST_K283);
+ ECTEST_NAMED_GF2M("NIST-B283", ECCurve_NIST_B283);
+ ECTEST_NAMED_GF2M("NIST-K409", ECCurve_NIST_K409);
+ ECTEST_NAMED_GF2M("NIST-B409", ECCurve_NIST_B409);
+ ECTEST_NAMED_GF2M("NIST-K571", ECCurve_NIST_K571);
+ ECTEST_NAMED_GF2M("NIST-B571", ECCurve_NIST_B571);
+ ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB163V1", ECCurve_X9_62_CHAR2_PNB163V1);
+ ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB163V2", ECCurve_X9_62_CHAR2_PNB163V2);
+ ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB163V3", ECCurve_X9_62_CHAR2_PNB163V3);
+ ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB176V1", ECCurve_X9_62_CHAR2_PNB176V1);
+ ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB191V1", ECCurve_X9_62_CHAR2_TNB191V1);
+ ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB191V2", ECCurve_X9_62_CHAR2_TNB191V2);
+ ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB191V3", ECCurve_X9_62_CHAR2_TNB191V3);
+ ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB208W1", ECCurve_X9_62_CHAR2_PNB208W1);
+ ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB239V1", ECCurve_X9_62_CHAR2_TNB239V1);
+ ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB239V2", ECCurve_X9_62_CHAR2_TNB239V2);
+ ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB239V3", ECCurve_X9_62_CHAR2_TNB239V3);
+ ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB272W1", ECCurve_X9_62_CHAR2_PNB272W1);
+ ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB304W1", ECCurve_X9_62_CHAR2_PNB304W1);
+ ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB359V1", ECCurve_X9_62_CHAR2_TNB359V1);
+ ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB368W1", ECCurve_X9_62_CHAR2_PNB368W1);
+ ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB431R1", ECCurve_X9_62_CHAR2_TNB431R1);
+ ECTEST_NAMED_GF2M("SECT-113R1", ECCurve_SECG_CHAR2_113R1);
+ ECTEST_NAMED_GF2M("SECT-113R2", ECCurve_SECG_CHAR2_113R2);
+ ECTEST_NAMED_GF2M("SECT-131R1", ECCurve_SECG_CHAR2_131R1);
+ ECTEST_NAMED_GF2M("SECT-131R2", ECCurve_SECG_CHAR2_131R2);
+ ECTEST_NAMED_GF2M("SECT-163K1", ECCurve_SECG_CHAR2_163K1);
+ ECTEST_NAMED_GF2M("SECT-163R1", ECCurve_SECG_CHAR2_163R1);
+ ECTEST_NAMED_GF2M("SECT-163R2", ECCurve_SECG_CHAR2_163R2);
+ ECTEST_NAMED_GF2M("SECT-193R1", ECCurve_SECG_CHAR2_193R1);
+ ECTEST_NAMED_GF2M("SECT-193R2", ECCurve_SECG_CHAR2_193R2);
+ ECTEST_NAMED_GF2M("SECT-233K1", ECCurve_SECG_CHAR2_233K1);
+ ECTEST_NAMED_GF2M("SECT-233R1", ECCurve_SECG_CHAR2_233R1);
+ ECTEST_NAMED_GF2M("SECT-239K1", ECCurve_SECG_CHAR2_239K1);
+ ECTEST_NAMED_GF2M("SECT-283K1", ECCurve_SECG_CHAR2_283K1);
+ ECTEST_NAMED_GF2M("SECT-283R1", ECCurve_SECG_CHAR2_283R1);
+ ECTEST_NAMED_GF2M("SECT-409K1", ECCurve_SECG_CHAR2_409K1);
+ ECTEST_NAMED_GF2M("SECT-409R1", ECCurve_SECG_CHAR2_409R1);
+ ECTEST_NAMED_GF2M("SECT-571K1", ECCurve_SECG_CHAR2_571K1);
+ ECTEST_NAMED_GF2M("SECT-571R1", ECCurve_SECG_CHAR2_571R1);
+ ECTEST_NAMED_GF2M("WTLS-1 (113)", ECCurve_WTLS_1);
+ ECTEST_NAMED_GF2M("WTLS-3 (163)", ECCurve_WTLS_3);
+ ECTEST_NAMED_GF2M("WTLS-4 (113)", ECCurve_WTLS_4);
+ ECTEST_NAMED_GF2M("WTLS-5 (163)", ECCurve_WTLS_5);
+ ECTEST_NAMED_GF2M("WTLS-10 (233)", ECCurve_WTLS_10);
+ ECTEST_NAMED_GF2M("WTLS-11 (233)", ECCurve_WTLS_11);
+
+ CLEANUP:
+ EC_FreeCurveParams(params);
+ ECGroup_free(group);
+ if (res != MP_OKAY) {
+ printf("Error: exiting with error value %i\n", res);
+ }
+ return res;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/tests/ec_naft.c b/mozilla/security/nss/lib/freebl/ecl/tests/ec_naft.c
new file mode 100644
index 0000000..490794d
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/tests/ec_naft.c
@@ -0,0 +1,151 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "mpi.h"
+#include "mplogic.h"
+#include "ecl.h"
+#include "ecp.h"
+#include "ecl-priv.h"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+/* Returns 2^e as an integer. This is meant to be used for small powers of
+ * two. */
+int ec_twoTo(int e);
+
+/* Number of bits of scalar to test */
+#define BITSIZE 160
+
+/* Time k repetitions of operation op. */
+#define M_TimeOperation(op, k) { \
+ double dStart, dNow, dUserTime; \
+ struct rusage ru; \
+ int i; \
+ getrusage(RUSAGE_SELF, &ru); \
+ dStart = (double)ru.ru_utime.tv_sec+(double)ru.ru_utime.tv_usec*0.000001; \
+ for (i = 0; i < k; i++) { \
+ { op; } \
+ }; \
+ getrusage(RUSAGE_SELF, &ru); \
+ dNow = (double)ru.ru_utime.tv_sec+(double)ru.ru_utime.tv_usec*0.000001; \
+ dUserTime = dNow-dStart; \
+ if (dUserTime) printf(" %-45s\n k: %6i, t: %6.2f sec\n", #op, k, dUserTime); \
+}
+
+/* Tests wNAF computation. Non-adjacent-form 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
+main(void)
+{
+ signed char naf[BITSIZE + 1];
+ ECGroup *group = NULL;
+ mp_int k;
+ mp_int *scalar;
+ int i, count;
+ int res;
+ int w = 5;
+ char s[1000];
+
+ /* Get a 160 bit scalar to compute wNAF from */
+ group = ECGroup_fromName(ECCurve_SECG_PRIME_160R1);
+ scalar = &group->genx;
+
+ /* Compute wNAF representation of scalar */
+ ec_compute_wNAF(naf, BITSIZE, scalar, w);
+
+ /* Verify correctness of representation */
+ mp_init(&k); /* init k to 0 */
+
+ for (i = BITSIZE; i >= 0; i--) {
+ mp_add(&k, &k, &k);
+ /* digits in mp_???_d are unsigned */
+ if (naf[i] >= 0) {
+ mp_add_d(&k, naf[i], &k);
+ } else {
+ mp_sub_d(&k, -naf[i], &k);
+ }
+ }
+
+ if (mp_cmp(&k, scalar) != 0) {
+ printf("Error: incorrect NAF value.\n");
+ MP_CHECKOK(mp_toradix(&k, s, 16));
+ printf("NAF value %s\n", s);
+ MP_CHECKOK(mp_toradix(scalar, s, 16));
+ printf("original value %s\n", s);
+ goto CLEANUP;
+ }
+
+ /* Verify digits of representation are valid */
+ for (i = 0; i <= BITSIZE; i++) {
+ if (naf[i] % 2 == 0 && naf[i] != 0) {
+ printf("Error: Even non-zero digit found.\n");
+ goto CLEANUP;
+ }
+ if (naf[i] < -(ec_twoTo(w - 1)) || naf[i] >= ec_twoTo(w - 1)) {
+ printf("Error: Magnitude of naf digit too large.\n");
+ goto CLEANUP;
+ }
+ }
+
+ /* Verify sparsity of representation */
+ count = w - 1;
+ for (i = 0; i <= BITSIZE; i++) {
+ if (naf[i] != 0) {
+ if (count < w - 1) {
+ printf("Error: Sparsity failed.\n");
+ goto CLEANUP;
+ }
+ count = 0;
+ } else
+ count++;
+ }
+
+ /* Check timing */
+ M_TimeOperation(ec_compute_wNAF(naf, BITSIZE, scalar, w), 10000);
+
+ printf("Test passed.\n");
+ CLEANUP:
+ ECGroup_free(group);
+ return MP_OKAY;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/tests/ecp_fpt.c b/mozilla/security/nss/lib/freebl/ecl/tests/ecp_fpt.c
new file mode 100644
index 0000000..538f4d0
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/tests/ecp_fpt.c
@@ -0,0 +1,1123 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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 using floating point operations.
+ *
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ecp_fp.h"
+#include "mpprime.h"
+
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+/* Time k repetitions of operation op. */
+#define M_TimeOperation(op, k) { \
+ double dStart, dNow, dUserTime; \
+ struct rusage ru; \
+ int i; \
+ getrusage(RUSAGE_SELF, &ru); \
+ dStart = (double)ru.ru_utime.tv_sec+(double)ru.ru_utime.tv_usec*0.000001; \
+ for (i = 0; i < k; i++) { \
+ { op; } \
+ }; \
+ getrusage(RUSAGE_SELF, &ru); \
+ dNow = (double)ru.ru_utime.tv_sec+(double)ru.ru_utime.tv_usec*0.000001; \
+ dUserTime = dNow-dStart; \
+ if (dUserTime) printf(" %-45s\n k: %6i, t: %6.2f sec, k/t: %6.2f ops/sec\n", #op, k, dUserTime, k/dUserTime); \
+}
+
+/* Test curve using specific floating point field arithmetic. */
+#define M_TestCurve(name_c, name) { \
+ printf("Testing %s using specific floating point implementation...\n", name_c); \
+ ECGroup_free(ecgroup); \
+ ecgroup = ECGroup_fromName(name); \
+ if (ecgroup == NULL) { \
+ printf(" Warning: could not construct group.\n"); \
+ printf("%s failed.\n", name_c); \
+ res = MP_NO; \
+ goto CLEANUP; \
+ } else { \
+ MP_CHECKOK( testCurve(ecgroup)); \
+ printf("%s passed.\n", name_c); \
+ } \
+}
+
+/* Outputs a floating point double (currently not used) */
+void
+d_output(const double *u, int len, char *name, const EC_group_fp * group)
+{
+ int i;
+
+ printf("%s: ", name);
+ for (i = 0; i < len; i++) {
+ printf("+ %.2f * 2^%i ", u[i] / ecfp_exp[i],
+ group->doubleBitSize * i);
+ }
+ printf("\n");
+}
+
+/* Tests a point p in Jacobian coordinates, comparing against the
+ * expected affine result (x, y). */
+mp_err
+testJacPoint(ecfp_jac_pt * p, mp_int *x, mp_int *y, ECGroup *ecgroup)
+{
+ char s[1000];
+ mp_int rx, ry, rz;
+ mp_err res = MP_OKAY;
+
+ MP_DIGITS(&rx) = 0;
+ MP_DIGITS(&ry) = 0;
+ MP_DIGITS(&rz) = 0;
+
+ MP_CHECKOK(mp_init(&rx));
+ MP_CHECKOK(mp_init(&ry));
+ MP_CHECKOK(mp_init(&rz));
+
+ ecfp_fp2i(&rx, p->x, ecgroup);
+ ecfp_fp2i(&ry, p->y, ecgroup);
+ ecfp_fp2i(&rz, p->z, ecgroup);
+
+ /* convert result R to affine coordinates */
+ ec_GFp_pt_jac2aff(&rx, &ry, &rz, &rx, &ry, ecgroup);
+
+ /* Compare to expected result */
+ if ((mp_cmp(&rx, x) != 0) || (mp_cmp(&ry, y) != 0)) {
+ printf(" Error: Jacobian Floating Point Incorrect.\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf("floating point result\nrx %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf("ry %s\n", s);
+ MP_CHECKOK(mp_toradix(x, s, 16));
+ printf("integer result\nx %s\n", s);
+ MP_CHECKOK(mp_toradix(y, s, 16));
+ printf("y %s\n", s);
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ CLEANUP:
+ mp_clear(&rx);
+ mp_clear(&ry);
+ mp_clear(&rz);
+
+ return res;
+}
+
+/* Tests a point p in Chudnovsky Jacobian coordinates, comparing against
+ * the expected affine result (x, y). */
+mp_err
+testChudPoint(ecfp_chud_pt * p, mp_int *x, mp_int *y, ECGroup *ecgroup)
+{
+
+ char s[1000];
+ mp_int rx, ry, rz, rz2, rz3, test;
+ mp_err res = MP_OKAY;
+
+ /* Initialization */
+ MP_DIGITS(&rx) = 0;
+ MP_DIGITS(&ry) = 0;
+ MP_DIGITS(&rz) = 0;
+ MP_DIGITS(&rz2) = 0;
+ MP_DIGITS(&rz3) = 0;
+ MP_DIGITS(&test) = 0;
+
+ MP_CHECKOK(mp_init(&rx));
+ MP_CHECKOK(mp_init(&ry));
+ MP_CHECKOK(mp_init(&rz));
+ MP_CHECKOK(mp_init(&rz2));
+ MP_CHECKOK(mp_init(&rz3));
+ MP_CHECKOK(mp_init(&test));
+
+ /* Convert to integers */
+ ecfp_fp2i(&rx, p->x, ecgroup);
+ ecfp_fp2i(&ry, p->y, ecgroup);
+ ecfp_fp2i(&rz, p->z, ecgroup);
+ ecfp_fp2i(&rz2, p->z2, ecgroup);
+ ecfp_fp2i(&rz3, p->z3, ecgroup);
+
+ /* Verify z2, z3 are valid */
+ mp_sqrmod(&rz, &ecgroup->meth->irr, &test);
+ if (mp_cmp(&test, &rz2) != 0) {
+ printf(" Error: rzp2 not valid\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+ mp_mulmod(&test, &rz, &ecgroup->meth->irr, &test);
+ if (mp_cmp(&test, &rz3) != 0) {
+ printf(" Error: rzp2 not valid\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ /* convert result R to affine coordinates */
+ ec_GFp_pt_jac2aff(&rx, &ry, &rz, &rx, &ry, ecgroup);
+
+ /* Compare against expected result */
+ if ((mp_cmp(&rx, x) != 0) || (mp_cmp(&ry, y) != 0)) {
+ printf(" Error: Chudnovsky Floating Point Incorrect.\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf("floating point result\nrx %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf("ry %s\n", s);
+ MP_CHECKOK(mp_toradix(x, s, 16));
+ printf("integer result\nx %s\n", s);
+ MP_CHECKOK(mp_toradix(y, s, 16));
+ printf("y %s\n", s);
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ CLEANUP:
+ mp_clear(&rx);
+ mp_clear(&ry);
+ mp_clear(&rz);
+ mp_clear(&rz2);
+ mp_clear(&rz3);
+ mp_clear(&test);
+
+ return res;
+}
+
+/* Tests a point p in Modified Jacobian coordinates, comparing against the
+ * expected affine result (x, y). */
+mp_err
+testJmPoint(ecfp_jm_pt * r, mp_int *x, mp_int *y, ECGroup *ecgroup)
+{
+
+ char s[1000];
+ mp_int rx, ry, rz, raz4, test;
+ mp_err res = MP_OKAY;
+
+ /* Initialization */
+ MP_DIGITS(&rx) = 0;
+ MP_DIGITS(&ry) = 0;
+ MP_DIGITS(&rz) = 0;
+ MP_DIGITS(&raz4) = 0;
+ MP_DIGITS(&test) = 0;
+
+ MP_CHECKOK(mp_init(&rx));
+ MP_CHECKOK(mp_init(&ry));
+ MP_CHECKOK(mp_init(&rz));
+ MP_CHECKOK(mp_init(&raz4));
+ MP_CHECKOK(mp_init(&test));
+
+ /* Convert to integer */
+ ecfp_fp2i(&rx, r->x, ecgroup);
+ ecfp_fp2i(&ry, r->y, ecgroup);
+ ecfp_fp2i(&rz, r->z, ecgroup);
+ ecfp_fp2i(&raz4, r->az4, ecgroup);
+
+ /* Verify raz4 = rz^4 * a */
+ mp_sqrmod(&rz, &ecgroup->meth->irr, &test);
+ mp_sqrmod(&test, &ecgroup->meth->irr, &test);
+ mp_mulmod(&test, &ecgroup->curvea, &ecgroup->meth->irr, &test);
+ if (mp_cmp(&test, &raz4) != 0) {
+ printf(" Error: a*z^4 not valid\n");
+ MP_CHECKOK(mp_toradix(&ecgroup->curvea, s, 16));
+ printf("a %s\n", s);
+ MP_CHECKOK(mp_toradix(&rz, s, 16));
+ printf("rz %s\n", s);
+ MP_CHECKOK(mp_toradix(&raz4, s, 16));
+ printf("raz4 %s\n", s);
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ /* convert result R to affine coordinates */
+ ec_GFp_pt_jac2aff(&rx, &ry, &rz, &rx, &ry, ecgroup);
+
+ /* Compare against expected result */
+ if ((mp_cmp(&rx, x) != 0) || (mp_cmp(&ry, y) != 0)) {
+ printf(" Error: Modified Jacobian Floating Point Incorrect.\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf("floating point result\nrx %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf("ry %s\n", s);
+ MP_CHECKOK(mp_toradix(x, s, 16));
+ printf("integer result\nx %s\n", s);
+ MP_CHECKOK(mp_toradix(y, s, 16));
+ printf("y %s\n", s);
+ res = MP_NO;
+ goto CLEANUP;
+ }
+ CLEANUP:
+ mp_clear(&rx);
+ mp_clear(&ry);
+ mp_clear(&rz);
+ mp_clear(&raz4);
+ mp_clear(&test);
+
+ return res;
+}
+
+/* Tests point addition of Jacobian + Affine -> Jacobian */
+mp_err
+testPointAddJacAff(ECGroup *ecgroup)
+{
+ mp_err res;
+ mp_int pz, rx2, ry2, rz2;
+ ecfp_jac_pt p, r;
+ ecfp_aff_pt q;
+ EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
+
+ /* Init */
+ MP_DIGITS(&pz) = 0;
+ MP_DIGITS(&rx2) = 0;
+ MP_DIGITS(&ry2) = 0;
+ MP_DIGITS(&rz2) = 0;
+ MP_CHECKOK(mp_init(&pz));
+ MP_CHECKOK(mp_init(&rx2));
+ MP_CHECKOK(mp_init(&ry2));
+ MP_CHECKOK(mp_init(&rz2));
+
+ MP_CHECKOK(mp_set_int(&pz, 5));
+
+ /* Set p */
+ ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
+ ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
+ ecfp_i2fp(p.z, &pz, ecgroup);
+ /* Set q */
+ ecfp_i2fp(q.x, &ecgroup->geny, ecgroup);
+ ecfp_i2fp(q.y, &ecgroup->genx, ecgroup);
+
+ /* Do calculations */
+ group->pt_add_jac_aff(&p, &q, &r, group);
+
+ /* Do calculation in integer to compare against */
+ MP_CHECKOK(ec_GFp_pt_add_jac_aff
+ (&ecgroup->genx, &ecgroup->geny, &pz, &ecgroup->geny,
+ &ecgroup->genx, &rx2, &ry2, &rz2, ecgroup));
+ /* convert result R to affine coordinates */
+ ec_GFp_pt_jac2aff(&rx2, &ry2, &rz2, &rx2, &ry2, ecgroup);
+
+ MP_CHECKOK(testJacPoint(&r, &rx2, &ry2, ecgroup));
+
+ CLEANUP:
+ if (res == MP_OKAY)
+ printf(" Test Passed - Point Addition - Jacobian & Affine\n");
+ else
+ printf("TEST FAILED - Point Addition - Jacobian & Affine\n");
+
+ mp_clear(&pz);
+ mp_clear(&rx2);
+ mp_clear(&ry2);
+ mp_clear(&rz2);
+
+ return res;
+}
+
+/* Tests point addition in Jacobian coordinates */
+mp_err
+testPointAddJac(ECGroup *ecgroup)
+{
+ mp_err res;
+ mp_int pz, qz, qx, qy, rx2, ry2, rz2;
+ ecfp_jac_pt p, q, r;
+ EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
+
+ /* Init */
+ MP_DIGITS(&pz) = 0;
+ MP_DIGITS(&qx) = 0;
+ MP_DIGITS(&qy) = 0;
+ MP_DIGITS(&qz) = 0;
+ MP_DIGITS(&rx2) = 0;
+ MP_DIGITS(&ry2) = 0;
+ MP_DIGITS(&rz2) = 0;
+ MP_CHECKOK(mp_init(&pz));
+ MP_CHECKOK(mp_init(&qx));
+ MP_CHECKOK(mp_init(&qy));
+ MP_CHECKOK(mp_init(&qz));
+ MP_CHECKOK(mp_init(&rx2));
+ MP_CHECKOK(mp_init(&ry2));
+ MP_CHECKOK(mp_init(&rz2));
+
+ MP_CHECKOK(mp_set_int(&pz, 5));
+ MP_CHECKOK(mp_set_int(&qz, 105));
+
+ /* Set p */
+ ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
+ ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
+ ecfp_i2fp(p.z, &pz, ecgroup);
+ /* Set q */
+ ecfp_i2fp(q.x, &ecgroup->geny, ecgroup);
+ ecfp_i2fp(q.y, &ecgroup->genx, ecgroup);
+ ecfp_i2fp(q.z, &qz, ecgroup);
+
+ /* Do calculations */
+ group->pt_add_jac(&p, &q, &r, group);
+
+ /* Do calculation in integer to compare against */
+ ec_GFp_pt_jac2aff(&ecgroup->geny, &ecgroup->genx, &qz, &qx, &qy,
+ ecgroup);
+ MP_CHECKOK(ec_GFp_pt_add_jac_aff
+ (&ecgroup->genx, &ecgroup->geny, &pz, &qx, &qy, &rx2, &ry2,
+ &rz2, ecgroup));
+ /* convert result R to affine coordinates */
+ ec_GFp_pt_jac2aff(&rx2, &ry2, &rz2, &rx2, &ry2, ecgroup);
+
+ MP_CHECKOK(testJacPoint(&r, &rx2, &ry2, ecgroup));
+
+ CLEANUP:
+ if (res == MP_OKAY)
+ printf(" Test Passed - Point Addition - Jacobian\n");
+ else
+ printf("TEST FAILED - Point Addition - Jacobian\n");
+
+ mp_clear(&pz);
+ mp_clear(&qx);
+ mp_clear(&qy);
+ mp_clear(&qz);
+ mp_clear(&rx2);
+ mp_clear(&ry2);
+ mp_clear(&rz2);
+
+ return res;
+}
+
+/* Tests point addition in Chudnovsky Jacobian Coordinates */
+mp_err
+testPointAddChud(ECGroup *ecgroup)
+{
+ mp_err res;
+ mp_int rx2, ry2, ix, iy, iz, test, pz, qx, qy, qz;
+ ecfp_chud_pt p, q, r;
+ EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
+
+ MP_DIGITS(&qx) = 0;
+ MP_DIGITS(&qy) = 0;
+ MP_DIGITS(&qz) = 0;
+ MP_DIGITS(&pz) = 0;
+ MP_DIGITS(&rx2) = 0;
+ MP_DIGITS(&ry2) = 0;
+ MP_DIGITS(&ix) = 0;
+ MP_DIGITS(&iy) = 0;
+ MP_DIGITS(&iz) = 0;
+ MP_DIGITS(&test) = 0;
+
+ MP_CHECKOK(mp_init(&qx));
+ MP_CHECKOK(mp_init(&qy));
+ MP_CHECKOK(mp_init(&qz));
+ MP_CHECKOK(mp_init(&pz));
+ MP_CHECKOK(mp_init(&rx2));
+ MP_CHECKOK(mp_init(&ry2));
+ MP_CHECKOK(mp_init(&ix));
+ MP_CHECKOK(mp_init(&iy));
+ MP_CHECKOK(mp_init(&iz));
+ MP_CHECKOK(mp_init(&test));
+
+ /* Test Chudnovsky form addition */
+ /* Set p */
+ MP_CHECKOK(mp_set_int(&pz, 5));
+ ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
+ ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
+ ecfp_i2fp(p.z, &pz, ecgroup);
+ mp_sqrmod(&pz, &ecgroup->meth->irr, &test);
+ ecfp_i2fp(p.z2, &test, ecgroup);
+ mp_mulmod(&test, &pz, &ecgroup->meth->irr, &test);
+ ecfp_i2fp(p.z3, &test, ecgroup);
+
+ /* Set q */
+ MP_CHECKOK(mp_set_int(&qz, 105));
+ ecfp_i2fp(q.x, &ecgroup->geny, ecgroup);
+ ecfp_i2fp(q.y, &ecgroup->genx, ecgroup);
+ ecfp_i2fp(q.z, &qz, ecgroup);
+ mp_sqrmod(&qz, &ecgroup->meth->irr, &test);
+ ecfp_i2fp(q.z2, &test, ecgroup);
+ mp_mulmod(&test, &qz, &ecgroup->meth->irr, &test);
+ ecfp_i2fp(q.z3, &test, ecgroup);
+
+ group->pt_add_chud(&p, &q, &r, group);
+
+ /* Calculate addition to compare against */
+ ec_GFp_pt_jac2aff(&ecgroup->geny, &ecgroup->genx, &qz, &qx, &qy,
+ ecgroup);
+ ec_GFp_pt_add_jac_aff(&ecgroup->genx, &ecgroup->geny, &pz, &qx, &qy,
+ &ix, &iy, &iz, ecgroup);
+ ec_GFp_pt_jac2aff(&ix, &iy, &iz, &rx2, &ry2, ecgroup);
+
+ MP_CHECKOK(testChudPoint(&r, &rx2, &ry2, ecgroup));
+
+ CLEANUP:
+ if (res == MP_OKAY)
+ printf(" Test Passed - Point Addition - Chudnovsky Jacobian\n");
+ else
+ printf("TEST FAILED - Point Addition - Chudnovsky Jacobian\n");
+
+ mp_clear(&qx);
+ mp_clear(&qy);
+ mp_clear(&qz);
+ mp_clear(&pz);
+ mp_clear(&rx2);
+ mp_clear(&ry2);
+ mp_clear(&ix);
+ mp_clear(&iy);
+ mp_clear(&iz);
+ mp_clear(&test);
+
+ return res;
+}
+
+/* Tests point addition in Modified Jacobian + Chudnovsky Jacobian ->
+ * Modified Jacobian coordinates. */
+mp_err
+testPointAddJmChud(ECGroup *ecgroup)
+{
+ mp_err res;
+ mp_int rx2, ry2, ix, iy, iz, test, pz, paz4, qx, qy, qz;
+ ecfp_chud_pt q;
+ ecfp_jm_pt p, r;
+ EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
+
+ MP_DIGITS(&qx) = 0;
+ MP_DIGITS(&qy) = 0;
+ MP_DIGITS(&qz) = 0;
+ MP_DIGITS(&pz) = 0;
+ MP_DIGITS(&paz4) = 0;
+ MP_DIGITS(&iz) = 0;
+ MP_DIGITS(&rx2) = 0;
+ MP_DIGITS(&ry2) = 0;
+ MP_DIGITS(&ix) = 0;
+ MP_DIGITS(&iy) = 0;
+ MP_DIGITS(&iz) = 0;
+ MP_DIGITS(&test) = 0;
+
+ MP_CHECKOK(mp_init(&qx));
+ MP_CHECKOK(mp_init(&qy));
+ MP_CHECKOK(mp_init(&qz));
+ MP_CHECKOK(mp_init(&pz));
+ MP_CHECKOK(mp_init(&paz4));
+ MP_CHECKOK(mp_init(&rx2));
+ MP_CHECKOK(mp_init(&ry2));
+ MP_CHECKOK(mp_init(&ix));
+ MP_CHECKOK(mp_init(&iy));
+ MP_CHECKOK(mp_init(&iz));
+ MP_CHECKOK(mp_init(&test));
+
+ /* Test Modified Jacobian form addition */
+ /* Set p */
+ ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
+ ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
+ ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup);
+ /* paz4 = az^4 */
+ MP_CHECKOK(mp_set_int(&pz, 5));
+ mp_sqrmod(&pz, &ecgroup->meth->irr, &paz4);
+ mp_sqrmod(&paz4, &ecgroup->meth->irr, &paz4);
+ mp_mulmod(&paz4, &ecgroup->curvea, &ecgroup->meth->irr, &paz4);
+ ecfp_i2fp(p.z, &pz, ecgroup);
+ ecfp_i2fp(p.az4, &paz4, ecgroup);
+
+ /* Set q */
+ MP_CHECKOK(mp_set_int(&qz, 105));
+ ecfp_i2fp(q.x, &ecgroup->geny, ecgroup);
+ ecfp_i2fp(q.y, &ecgroup->genx, ecgroup);
+ ecfp_i2fp(q.z, &qz, ecgroup);
+ mp_sqrmod(&qz, &ecgroup->meth->irr, &test);
+ ecfp_i2fp(q.z2, &test, ecgroup);
+ mp_mulmod(&test, &qz, &ecgroup->meth->irr, &test);
+ ecfp_i2fp(q.z3, &test, ecgroup);
+
+ /* Do calculation */
+ group->pt_add_jm_chud(&p, &q, &r, group);
+
+ /* Calculate addition to compare against */
+ ec_GFp_pt_jac2aff(&ecgroup->geny, &ecgroup->genx, &qz, &qx, &qy,
+ ecgroup);
+ ec_GFp_pt_add_jac_aff(&ecgroup->genx, &ecgroup->geny, &pz, &qx, &qy,
+ &ix, &iy, &iz, ecgroup);
+ ec_GFp_pt_jac2aff(&ix, &iy, &iz, &rx2, &ry2, ecgroup);
+
+ MP_CHECKOK(testJmPoint(&r, &rx2, &ry2, ecgroup));
+
+ CLEANUP:
+ if (res == MP_OKAY)
+ printf
+ (" Test Passed - Point Addition - Modified & Chudnovsky Jacobian\n");
+ else
+ printf
+ ("TEST FAILED - Point Addition - Modified & Chudnovsky Jacobian\n");
+
+ mp_clear(&qx);
+ mp_clear(&qy);
+ mp_clear(&qz);
+ mp_clear(&pz);
+ mp_clear(&paz4);
+ mp_clear(&rx2);
+ mp_clear(&ry2);
+ mp_clear(&ix);
+ mp_clear(&iy);
+ mp_clear(&iz);
+ mp_clear(&test);
+
+ return res;
+}
+
+/* Tests point doubling in Modified Jacobian coordinates */
+mp_err
+testPointDoubleJm(ECGroup *ecgroup)
+{
+ mp_err res;
+ mp_int pz, paz4, rx2, ry2, rz2, raz4;
+ ecfp_jm_pt p, r;
+ EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
+
+ MP_DIGITS(&pz) = 0;
+ MP_DIGITS(&paz4) = 0;
+ MP_DIGITS(&rx2) = 0;
+ MP_DIGITS(&ry2) = 0;
+ MP_DIGITS(&rz2) = 0;
+ MP_DIGITS(&raz4) = 0;
+
+ MP_CHECKOK(mp_init(&pz));
+ MP_CHECKOK(mp_init(&paz4));
+ MP_CHECKOK(mp_init(&rx2));
+ MP_CHECKOK(mp_init(&ry2));
+ MP_CHECKOK(mp_init(&rz2));
+ MP_CHECKOK(mp_init(&raz4));
+
+ /* Set p */
+ ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
+ ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
+ ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup);
+
+ /* paz4 = az^4 */
+ MP_CHECKOK(mp_set_int(&pz, 5));
+ mp_sqrmod(&pz, &ecgroup->meth->irr, &paz4);
+ mp_sqrmod(&paz4, &ecgroup->meth->irr, &paz4);
+ mp_mulmod(&paz4, &ecgroup->curvea, &ecgroup->meth->irr, &paz4);
+
+ ecfp_i2fp(p.z, &pz, ecgroup);
+ ecfp_i2fp(p.az4, &paz4, ecgroup);
+
+ group->pt_dbl_jm(&p, &r, group);
+
+ M_TimeOperation(group->pt_dbl_jm(&p, &r, group), 100000);
+
+ /* Calculate doubling to compare against */
+ ec_GFp_pt_dbl_jac(&ecgroup->genx, &ecgroup->geny, &pz, &rx2, &ry2,
+ &rz2, ecgroup);
+ ec_GFp_pt_jac2aff(&rx2, &ry2, &rz2, &rx2, &ry2, ecgroup);
+
+ /* Do comparison and check az^4 */
+ MP_CHECKOK(testJmPoint(&r, &rx2, &ry2, ecgroup));
+
+ CLEANUP:
+ if (res == MP_OKAY)
+ printf(" Test Passed - Point Doubling - Modified Jacobian\n");
+ else
+ printf("TEST FAILED - Point Doubling - Modified Jacobian\n");
+ mp_clear(&pz);
+ mp_clear(&paz4);
+ mp_clear(&rx2);
+ mp_clear(&ry2);
+ mp_clear(&rz2);
+ mp_clear(&raz4);
+
+ return res;
+
+}
+
+/* Tests point doubling in Chudnovsky Jacobian coordinates */
+mp_err
+testPointDoubleChud(ECGroup *ecgroup)
+{
+ mp_err res;
+ mp_int px, py, pz, rx2, ry2, rz2;
+ ecfp_aff_pt p;
+ ecfp_chud_pt p2;
+ EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
+
+ MP_DIGITS(&rx2) = 0;
+ MP_DIGITS(&ry2) = 0;
+ MP_DIGITS(&rz2) = 0;
+ MP_DIGITS(&px) = 0;
+ MP_DIGITS(&py) = 0;
+ MP_DIGITS(&pz) = 0;
+
+ MP_CHECKOK(mp_init(&rx2));
+ MP_CHECKOK(mp_init(&ry2));
+ MP_CHECKOK(mp_init(&rz2));
+ MP_CHECKOK(mp_init(&px));
+ MP_CHECKOK(mp_init(&py));
+ MP_CHECKOK(mp_init(&pz));
+
+ /* Set p2 = 2P */
+ ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
+ ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
+ ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup);
+
+ group->pt_dbl_aff2chud(&p, &p2, group);
+
+ /* Calculate doubling to compare against */
+ MP_CHECKOK(mp_set_int(&pz, 1));
+ ec_GFp_pt_dbl_jac(&ecgroup->genx, &ecgroup->geny, &pz, &rx2, &ry2,
+ &rz2, ecgroup);
+ ec_GFp_pt_jac2aff(&rx2, &ry2, &rz2, &rx2, &ry2, ecgroup);
+
+ /* Do comparison and check az^4 */
+ MP_CHECKOK(testChudPoint(&p2, &rx2, &ry2, ecgroup));
+
+ CLEANUP:
+ if (res == MP_OKAY)
+ printf(" Test Passed - Point Doubling - Chudnovsky Jacobian\n");
+ else
+ printf("TEST FAILED - Point Doubling - Chudnovsky Jacobian\n");
+
+ mp_clear(&rx2);
+ mp_clear(&ry2);
+ mp_clear(&rz2);
+ mp_clear(&px);
+ mp_clear(&py);
+ mp_clear(&pz);
+
+ return res;
+}
+
+/* Test point doubling in Jacobian coordinates */
+mp_err
+testPointDoubleJac(ECGroup *ecgroup)
+{
+ mp_err res;
+ mp_int pz, rx, ry, rz, rx2, ry2, rz2;
+ ecfp_jac_pt p, p2;
+ EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
+
+ MP_DIGITS(&pz) = 0;
+ MP_DIGITS(&rx) = 0;
+ MP_DIGITS(&ry) = 0;
+ MP_DIGITS(&rz) = 0;
+ MP_DIGITS(&rx2) = 0;
+ MP_DIGITS(&ry2) = 0;
+ MP_DIGITS(&rz2) = 0;
+
+ MP_CHECKOK(mp_init(&pz));
+ MP_CHECKOK(mp_init(&rx));
+ MP_CHECKOK(mp_init(&ry));
+ MP_CHECKOK(mp_init(&rz));
+ MP_CHECKOK(mp_init(&rx2));
+ MP_CHECKOK(mp_init(&ry2));
+ MP_CHECKOK(mp_init(&rz2));
+
+ MP_CHECKOK(mp_set_int(&pz, 5));
+
+ /* Set p2 = 2P */
+ ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
+ ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
+ ecfp_i2fp(p.z, &pz, ecgroup);
+ ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup);
+
+ group->pt_dbl_jac(&p, &p2, group);
+ M_TimeOperation(group->pt_dbl_jac(&p, &p2, group), 100000);
+
+ /* Calculate doubling to compare against */
+ ec_GFp_pt_dbl_jac(&ecgroup->genx, &ecgroup->geny, &pz, &rx2, &ry2,
+ &rz2, ecgroup);
+ ec_GFp_pt_jac2aff(&rx2, &ry2, &rz2, &rx2, &ry2, ecgroup);
+
+ /* Do comparison */
+ MP_CHECKOK(testJacPoint(&p2, &rx2, &ry2, ecgroup));
+
+ CLEANUP:
+ if (res == MP_OKAY)
+ printf(" Test Passed - Point Doubling - Jacobian\n");
+ else
+ printf("TEST FAILED - Point Doubling - Jacobian\n");
+
+ mp_clear(&pz);
+ mp_clear(&rx);
+ mp_clear(&ry);
+ mp_clear(&rz);
+ mp_clear(&rx2);
+ mp_clear(&ry2);
+ mp_clear(&rz2);
+
+ return res;
+}
+
+/* Tests a point multiplication (various algorithms) */
+mp_err
+testPointMul(ECGroup *ecgroup)
+{
+ mp_err res;
+ char s[1000];
+ mp_int rx, ry, order_1;
+
+ /* Init */
+ MP_DIGITS(&rx) = 0;
+ MP_DIGITS(&ry) = 0;
+ MP_DIGITS(&order_1) = 0;
+
+ MP_CHECKOK(mp_init(&rx));
+ MP_CHECKOK(mp_init(&ry));
+ MP_CHECKOK(mp_init(&order_1));
+
+ MP_CHECKOK(mp_set_int(&order_1, 1));
+ MP_CHECKOK(mp_sub(&ecgroup->order, &order_1, &order_1));
+
+ /* Test Algorithm 1: Jacobian-Affine Double & Add */
+ ec_GFp_pt_mul_jac_fp(&order_1, &ecgroup->genx, &ecgroup->geny, &rx,
+ &ry, ecgroup);
+ MP_CHECKOK(ecgroup->meth->field_neg(&ry, &ry, ecgroup->meth));
+ if ((mp_cmp(&rx, &ecgroup->genx) != 0)
+ || (mp_cmp(&ry, &ecgroup->geny) != 0)) {
+ printf
+ (" Error: ec_GFp_pt_mul_jac_fp invalid result (expected (- base point)).\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf("rx %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf("ry %s\n", s);
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ ec_GFp_pt_mul_jac_fp(&ecgroup->order, &ecgroup->genx, &ecgroup->geny,
+ &rx, &ry, ecgroup);
+ if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
+ printf
+ (" Error: ec_GFp_pt_mul_jac_fp invalid result (expected point at infinity.\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf("rx %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf("ry %s\n", s);
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ /* Test Algorithm 2: 4-bit Window in Jacobian */
+ ec_GFp_point_mul_jac_4w_fp(&order_1, &ecgroup->genx, &ecgroup->geny,
+ &rx, &ry, ecgroup);
+ MP_CHECKOK(ecgroup->meth->field_neg(&ry, &ry, ecgroup->meth));
+ if ((mp_cmp(&rx, &ecgroup->genx) != 0)
+ || (mp_cmp(&ry, &ecgroup->geny) != 0)) {
+ printf
+ (" Error: ec_GFp_point_mul_jac_4w_fp invalid result (expected (- base point)).\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf("rx %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf("ry %s\n", s);
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ ec_GFp_point_mul_jac_4w_fp(&ecgroup->order, &ecgroup->genx,
+ &ecgroup->geny, &rx, &ry, ecgroup);
+ if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
+ printf
+ (" Error: ec_GFp_point_mul_jac_4w_fp invalid result (expected point at infinity.\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf("rx %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf("ry %s\n", s);
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ /* Test Algorithm 3: wNAF with modified Jacobian coordinates */
+ ec_GFp_point_mul_wNAF_fp(&order_1, &ecgroup->genx, &ecgroup->geny, &rx,
+ &ry, ecgroup);
+ MP_CHECKOK(ecgroup->meth->field_neg(&ry, &ry, ecgroup->meth));
+ if ((mp_cmp(&rx, &ecgroup->genx) != 0)
+ || (mp_cmp(&ry, &ecgroup->geny) != 0)) {
+ printf
+ (" Error: ec_GFp_pt_mul_wNAF_fp invalid result (expected (- base point)).\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf("rx %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf("ry %s\n", s);
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ ec_GFp_point_mul_wNAF_fp(&ecgroup->order, &ecgroup->genx,
+ &ecgroup->geny, &rx, &ry, ecgroup);
+ if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
+ printf
+ (" Error: ec_GFp_pt_mul_wNAF_fp invalid result (expected point at infinity.\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf("rx %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf("ry %s\n", s);
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ CLEANUP:
+ if (res == MP_OKAY)
+ printf(" Test Passed - Point Multiplication\n");
+ else
+ printf("TEST FAILED - Point Multiplication\n");
+ mp_clear(&rx);
+ mp_clear(&ry);
+ mp_clear(&order_1);
+
+ return res;
+}
+
+/* Tests point multiplication with a random scalar repeatedly, comparing
+ * for consistency within different algorithms. */
+mp_err
+testPointMulRandom(ECGroup *ecgroup)
+{
+ mp_err res;
+ mp_int rx, ry, rx2, ry2, n;
+ int i, size;
+ EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
+
+ MP_DIGITS(&rx) = 0;
+ MP_DIGITS(&ry) = 0;
+ MP_DIGITS(&rx2) = 0;
+ MP_DIGITS(&ry2) = 0;
+ MP_DIGITS(&n) = 0;
+
+ MP_CHECKOK(mp_init(&rx));
+ MP_CHECKOK(mp_init(&ry));
+ MP_CHECKOK(mp_init(&rx2));
+ MP_CHECKOK(mp_init(&ry2));
+ MP_CHECKOK(mp_init(&n));
+
+ for (i = 0; i < 100; i++) {
+ /* compute random scalar */
+ size = mpl_significant_bits(&ecgroup->meth->irr);
+ if (size < MP_OKAY) {
+ res = MP_NO;
+ goto CLEANUP;
+ }
+ MP_CHECKOK(mpp_random_size(&n, group->orderBitSize));
+ MP_CHECKOK(mp_mod(&n, &ecgroup->order, &n));
+
+ ec_GFp_pt_mul_jac(&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry,
+ ecgroup);
+ ec_GFp_pt_mul_jac_fp(&n, &ecgroup->genx, &ecgroup->geny, &rx2,
+ &ry2, ecgroup);
+
+ if ((mp_cmp(&rx, &rx2) != 0) || (mp_cmp(&ry, &ry2) != 0)) {
+ printf
+ (" Error: different results for Point Multiplication - Double & Add.\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ ec_GFp_point_mul_wNAF_fp(&n, &ecgroup->genx, &ecgroup->geny, &rx,
+ &ry, ecgroup);
+ if ((mp_cmp(&rx, &rx2) != 0) || (mp_cmp(&ry, &ry2) != 0)) {
+ printf
+ (" Error: different results for Point Multiplication - wNAF.\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ ec_GFp_point_mul_jac_4w_fp(&n, &ecgroup->genx, &ecgroup->geny, &rx,
+ &ry, ecgroup);
+ if ((mp_cmp(&rx, &rx2) != 0) || (mp_cmp(&ry, &ry2) != 0)) {
+ printf
+ (" Error: different results for Point Multiplication - 4 bit window.\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ }
+
+ CLEANUP:
+ if (res == MP_OKAY)
+ printf(" Test Passed - Point Random Multiplication\n");
+ else
+ printf("TEST FAILED - Point Random Multiplication\n");
+ mp_clear(&rx);
+ mp_clear(&ry);
+ mp_clear(&rx2);
+ mp_clear(&ry2);
+ mp_clear(&n);
+
+ return res;
+}
+
+/* Tests the time required for a point multiplication */
+mp_err
+testPointMulTime(ECGroup *ecgroup)
+{
+ mp_err res = MP_OKAY;
+ mp_int rx, ry, n;
+ int size;
+
+ MP_DIGITS(&rx) = 0;
+ MP_DIGITS(&ry) = 0;
+ MP_DIGITS(&n) = 0;
+
+ MP_CHECKOK(mp_init(&rx));
+ MP_CHECKOK(mp_init(&ry));
+ MP_CHECKOK(mp_init(&n));
+
+ /* compute random scalar */
+ size = mpl_significant_bits(&ecgroup->meth->irr);
+ if (size < MP_OKAY) {
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ MP_CHECKOK(mpp_random_size(&n, (size + ECL_BITS - 1) / ECL_BITS));
+ MP_CHECKOK(ecgroup->meth->field_mod(&n, &n, ecgroup->meth));
+
+ M_TimeOperation(ec_GFp_pt_mul_jac_fp
+ (&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry,
+ ecgroup), 1000);
+
+ M_TimeOperation(ec_GFp_point_mul_jac_4w_fp
+ (&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry,
+ ecgroup), 1000);
+
+ M_TimeOperation(ec_GFp_point_mul_wNAF_fp
+ (&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry,
+ ecgroup), 1000);
+
+ M_TimeOperation(ec_GFp_pt_mul_jac
+ (&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry,
+ ecgroup), 100);
+
+ CLEANUP:
+ if (res == MP_OKAY)
+ printf(" Test Passed - Point Multiplication Timing\n");
+ else
+ printf("TEST FAILED - Point Multiplication Timing\n");
+ mp_clear(&rx);
+ mp_clear(&ry);
+ mp_clear(&n);
+
+ return res;
+}
+
+/* Tests pre computation of Chudnovsky Jacobian points used in wNAF form */
+mp_err
+testPreCompute(ECGroup *ecgroup)
+{
+ ecfp_chud_pt precomp[16];
+ ecfp_aff_pt p;
+ EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
+ int i;
+ mp_err res;
+
+ mp_int x, y, ny, x2, y2;
+
+ MP_DIGITS(&x) = 0;
+ MP_DIGITS(&y) = 0;
+ MP_DIGITS(&ny) = 0;
+ MP_DIGITS(&x2) = 0;
+ MP_DIGITS(&y2) = 0;
+
+ MP_CHECKOK(mp_init(&x));
+ MP_CHECKOK(mp_init(&y));
+ MP_CHECKOK(mp_init(&ny));
+ MP_CHECKOK(mp_init(&x2));
+ MP_CHECKOK(mp_init(&y2));
+
+ ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
+ ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
+ ecfp_i2fp(group->curvea, &(ecgroup->curvea), ecgroup);
+
+ /* Perform precomputation */
+ group->precompute_chud(precomp, &p, group);
+
+ M_TimeOperation(group->precompute_chud(precomp, &p, group), 10000);
+
+ /* Calculate addition to compare against */
+ MP_CHECKOK(mp_copy(&ecgroup->genx, &x));
+ MP_CHECKOK(mp_copy(&ecgroup->geny, &y));
+ MP_CHECKOK(ecgroup->meth->field_neg(&y, &ny, ecgroup->meth));
+
+ ec_GFp_pt_dbl_aff(&x, &y, &x2, &y2, ecgroup);
+
+ for (i = 0; i < 8; i++) {
+ MP_CHECKOK(testChudPoint(&precomp[8 + i], &x, &y, ecgroup));
+ MP_CHECKOK(testChudPoint(&precomp[7 - i], &x, &ny, ecgroup));
+ ec_GFp_pt_add_aff(&x, &y, &x2, &y2, &x, &y, ecgroup);
+ MP_CHECKOK(ecgroup->meth->field_neg(&y, &ny, ecgroup->meth));
+ }
+
+ CLEANUP:
+ if (res == MP_OKAY)
+ printf(" Test Passed - Precomputation\n");
+ else
+ printf("TEST FAILED - Precomputation\n");
+
+ mp_clear(&x);
+ mp_clear(&y);
+ mp_clear(&ny);
+ mp_clear(&x2);
+ mp_clear(&y2);
+ return res;
+}
+
+/* Given a curve using floating point arithmetic, test it. This method
+ * specifies which of the above tests to run. */
+mp_err
+testCurve(ECGroup *ecgroup)
+{
+ int res = MP_OKAY;
+
+ MP_CHECKOK(testPointAddJacAff(ecgroup));
+ MP_CHECKOK(testPointAddJac(ecgroup));
+ MP_CHECKOK(testPointAddChud(ecgroup));
+ MP_CHECKOK(testPointAddJmChud(ecgroup));
+ MP_CHECKOK(testPointDoubleJac(ecgroup));
+ MP_CHECKOK(testPointDoubleChud(ecgroup));
+ MP_CHECKOK(testPointDoubleJm(ecgroup));
+ MP_CHECKOK(testPreCompute(ecgroup));
+ MP_CHECKOK(testPointMul(ecgroup));
+ MP_CHECKOK(testPointMulRandom(ecgroup));
+ MP_CHECKOK(testPointMulTime(ecgroup));
+ CLEANUP:
+ return res;
+}
+
+/* Tests a number of curves optimized using floating point arithmetic */
+int
+main(void)
+{
+ mp_err res = MP_OKAY;
+ ECGroup *ecgroup = NULL;
+
+ /* specific arithmetic tests */
+ M_TestCurve("SECG-160R1", ECCurve_SECG_PRIME_160R1);
+ M_TestCurve("SECG-192R1", ECCurve_SECG_PRIME_192R1);
+ M_TestCurve("SEGC-224R1", ECCurve_SECG_PRIME_224R1);
+
+ CLEANUP:
+ ECGroup_free(ecgroup);
+ if (res != MP_OKAY) {
+ printf("Error: exiting with error value %i\n", res);
+ }
+ return res;
+}
diff --git a/mozilla/security/nss/lib/freebl/ecl/tests/ecp_test.c b/mozilla/security/nss/lib/freebl/ecl/tests/ecp_test.c
new file mode 100644
index 0000000..eb2844f
--- /dev/null
+++ b/mozilla/security/nss/lib/freebl/ecl/tests/ecp_test.c
@@ -0,0 +1,460 @@
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "mpi.h"
+#include "mplogic.h"
+#include "mpprime.h"
+#include "ecl.h"
+#include "ecl-curve.h"
+#include "ecp.h"
+#include <stdio.h>
+#include <strings.h>
+#include <assert.h>
+
+#include <time.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+/* Time k repetitions of operation op. */
+#define M_TimeOperation(op, k) { \
+ double dStart, dNow, dUserTime; \
+ struct rusage ru; \
+ int i; \
+ getrusage(RUSAGE_SELF, &ru); \
+ dStart = (double)ru.ru_utime.tv_sec+(double)ru.ru_utime.tv_usec*0.000001; \
+ for (i = 0; i < k; i++) { \
+ { op; } \
+ }; \
+ getrusage(RUSAGE_SELF, &ru); \
+ dNow = (double)ru.ru_utime.tv_sec+(double)ru.ru_utime.tv_usec*0.000001; \
+ dUserTime = dNow-dStart; \
+ if (dUserTime) printf(" %-45s k: %6i, t: %6.2f sec\n", #op, k, dUserTime); \
+}
+
+/* Test curve using generic field arithmetic. */
+#define ECTEST_GENERIC_GFP(name_c, name) \
+ printf("Testing %s using generic implementation...\n", name_c); \
+ params = EC_GetNamedCurveParams(name); \
+ if (params == NULL) { \
+ printf(" Error: could not construct params.\n"); \
+ res = MP_NO; \
+ goto CLEANUP; \
+ } \
+ ECGroup_free(group); \
+ group = ECGroup_fromHex(params); \
+ if (group == NULL) { \
+ printf(" Error: could not construct group.\n"); \
+ res = MP_NO; \
+ goto CLEANUP; \
+ } \
+ MP_CHECKOK( ectest_curve_GFp(group, ectestPrint, ectestTime, 1) ); \
+ printf("... okay.\n");
+
+/* Test curve using specific field arithmetic. */
+#define ECTEST_NAMED_GFP(name_c, name) \
+ printf("Testing %s using specific implementation...\n", name_c); \
+ ECGroup_free(group); \
+ group = ECGroup_fromName(name); \
+ if (group == NULL) { \
+ printf(" Warning: could not construct group.\n"); \
+ printf("... failed; continuing with remaining tests.\n"); \
+ } else { \
+ MP_CHECKOK( ectest_curve_GFp(group, ectestPrint, ectestTime, 0) ); \
+ printf("... okay.\n"); \
+ }
+
+/* Performs basic tests of elliptic curve cryptography over prime fields.
+ * If tests fail, then it prints an error message, aborts, and returns an
+ * error code. Otherwise, returns 0. */
+int
+ectest_curve_GFp(ECGroup *group, int ectestPrint, int ectestTime,
+ int generic)
+{
+
+ mp_int one, order_1, gx, gy, rx, ry, n;
+ int size;
+ mp_err res;
+ char s[1000];
+
+ /* initialize values */
+ MP_CHECKOK(mp_init(&one));
+ MP_CHECKOK(mp_init(&order_1));
+ MP_CHECKOK(mp_init(&gx));
+ MP_CHECKOK(mp_init(&gy));
+ MP_CHECKOK(mp_init(&rx));
+ MP_CHECKOK(mp_init(&ry));
+ MP_CHECKOK(mp_init(&n));
+
+ MP_CHECKOK(mp_set_int(&one, 1));
+ MP_CHECKOK(mp_sub(&group->order, &one, &order_1));
+
+ /* encode base point */
+ if (group->meth->field_dec) {
+ MP_CHECKOK(group->meth->field_dec(&group->genx, &gx, group->meth));
+ MP_CHECKOK(group->meth->field_dec(&group->geny, &gy, group->meth));
+ } else {
+ MP_CHECKOK(mp_copy(&group->genx, &gx));
+ MP_CHECKOK(mp_copy(&group->geny, &gy));
+ }
+ if (ectestPrint) {
+ /* output base point */
+ printf(" base point P:\n");
+ MP_CHECKOK(mp_toradix(&gx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&gy, s, 16));
+ printf(" %s\n", s);
+ if (group->meth->field_enc) {
+ printf(" base point P (encoded):\n");
+ MP_CHECKOK(mp_toradix(&group->genx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&group->geny, s, 16));
+ printf(" %s\n", s);
+ }
+ }
+
+#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
+ /* multiply base point by order - 1 and check for negative of base
+ * point */
+ MP_CHECKOK(ec_GFp_pt_mul_aff
+ (&order_1, &group->genx, &group->geny, &rx, &ry, group));
+ if (ectestPrint) {
+ printf(" (order-1)*P (affine):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ MP_CHECKOK(group->meth->field_neg(&ry, &ry, group->meth));
+ if ((mp_cmp(&rx, &group->genx) != 0)
+ || (mp_cmp(&ry, &group->geny) != 0)) {
+ printf(" Error: invalid result (expected (- base point)).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+#endif
+
+#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
+ /* multiply base point by order - 1 and check for negative of base
+ * point */
+ MP_CHECKOK(ec_GFp_pt_mul_jac
+ (&order_1, &group->genx, &group->geny, &rx, &ry, group));
+ if (ectestPrint) {
+ printf(" (order-1)*P (jacobian):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ MP_CHECKOK(group->meth->field_neg(&ry, &ry, group->meth));
+ if ((mp_cmp(&rx, &group->genx) != 0)
+ || (mp_cmp(&ry, &group->geny) != 0)) {
+ printf(" Error: invalid result (expected (- base point)).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+#endif
+
+ /* multiply base point by order - 1 and check for negative of base
+ * point */
+ MP_CHECKOK(ECPoint_mul(group, &order_1, NULL, NULL, &rx, &ry));
+ if (ectestPrint) {
+ printf(" (order-1)*P (ECPoint_mul):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry));
+ if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) {
+ printf(" Error: invalid result (expected (- base point)).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ /* multiply base point by order - 1 and check for negative of base
+ * point */
+ MP_CHECKOK(ECPoint_mul(group, &order_1, &gx, &gy, &rx, &ry));
+ if (ectestPrint) {
+ printf(" (order-1)*P (ECPoint_mul):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry));
+ if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) {
+ printf(" Error: invalid result (expected (- base point)).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
+ /* multiply base point by order and check for point at infinity */
+ MP_CHECKOK(ec_GFp_pt_mul_aff
+ (&group->order, &group->genx, &group->geny, &rx, &ry,
+ group));
+ if (ectestPrint) {
+ printf(" (order)*P (affine):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
+ printf(" Error: invalid result (expected point at infinity).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+#endif
+
+#ifdef ECL_ENABLE_GFP_PT_MUL_JAC
+ /* multiply base point by order and check for point at infinity */
+ MP_CHECKOK(ec_GFp_pt_mul_jac
+ (&group->order, &group->genx, &group->geny, &rx, &ry,
+ group));
+ if (ectestPrint) {
+ printf(" (order)*P (jacobian):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
+ printf(" Error: invalid result (expected point at infinity).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+#endif
+
+ /* multiply base point by order and check for point at infinity */
+ MP_CHECKOK(ECPoint_mul(group, &group->order, NULL, NULL, &rx, &ry));
+ if (ectestPrint) {
+ printf(" (order)*P (ECPoint_mul):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
+ printf(" Error: invalid result (expected point at infinity).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ /* multiply base point by order and check for point at infinity */
+ MP_CHECKOK(ECPoint_mul(group, &group->order, &gx, &gy, &rx, &ry));
+ if (ectestPrint) {
+ printf(" (order)*P (ECPoint_mul):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
+ printf(" Error: invalid result (expected point at infinity).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ /* check that (order-1)P + (order-1)P + P == (order-1)P */
+ MP_CHECKOK(ECPoints_mul
+ (group, &order_1, &order_1, &gx, &gy, &rx, &ry));
+ MP_CHECKOK(ECPoints_mul(group, &one, &one, &rx, &ry, &rx, &ry));
+ if (ectestPrint) {
+ printf
+ (" (order-1)*P + (order-1)*P + P == (order-1)*P (ECPoints_mul):\n");
+ MP_CHECKOK(mp_toradix(&rx, s, 16));
+ printf(" %s\n", s);
+ MP_CHECKOK(mp_toradix(&ry, s, 16));
+ printf(" %s\n", s);
+ }
+ MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry));
+ if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) {
+ printf(" Error: invalid result (expected (- base point)).\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ /* test validate_point function */
+ if (ECPoint_validate(group, &gx, &gy) != MP_YES) {
+ printf(" Error: validate point on base point failed.\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+ MP_CHECKOK(mp_add_d(&gy, 1, &ry));
+ if (ECPoint_validate(group, &gx, &ry) != MP_NO) {
+ printf(" Error: validate point on invalid point passed.\n");
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ if (ectestTime) {
+ /* compute random scalar */
+ size = mpl_significant_bits(&group->meth->irr);
+ if (size < MP_OKAY) {
+ goto CLEANUP;
+ }
+ MP_CHECKOK(mpp_random_size(&n, (size + ECL_BITS - 1) / ECL_BITS));
+ MP_CHECKOK(group->meth->field_mod(&n, &n, group->meth));
+ /* timed test */
+ if (generic) {
+#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
+ M_TimeOperation(MP_CHECKOK
+ (ec_GFp_pt_mul_aff
+ (&n, &group->genx, &group->geny, &rx, &ry,
+ group)), 100);
+#endif
+ M_TimeOperation(MP_CHECKOK
+ (ECPoint_mul(group, &n, NULL, NULL, &rx, &ry)),
+ 100);
+ M_TimeOperation(MP_CHECKOK
+ (ECPoints_mul
+ (group, &n, &n, &gx, &gy, &rx, &ry)), 100);
+ } else {
+ M_TimeOperation(MP_CHECKOK
+ (ECPoint_mul(group, &n, NULL, NULL, &rx, &ry)),
+ 100);
+ M_TimeOperation(MP_CHECKOK
+ (ECPoint_mul(group, &n, &gx, &gy, &rx, &ry)),
+ 100);
+ M_TimeOperation(MP_CHECKOK
+ (ECPoints_mul
+ (group, &n, &n, &gx, &gy, &rx, &ry)), 100);
+ }
+ }
+
+ CLEANUP:
+ mp_clear(&one);
+ mp_clear(&order_1);
+ mp_clear(&gx);
+ mp_clear(&gy);
+ mp_clear(&rx);
+ mp_clear(&ry);
+ mp_clear(&n);
+ if (res != MP_OKAY) {
+ printf(" Error: exiting with error value %i\n", res);
+ }
+ return res;
+}
+
+/* Prints help information. */
+void
+printUsage()
+{
+ printf("Usage: ecp_test [--print] [--time]\n");
+ printf
+ (" --print Print out results of each point arithmetic test.\n");
+ printf
+ (" --time Benchmark point operations and print results.\n");
+}
+
+/* Performs tests of elliptic curve cryptography over prime fields If
+ * tests fail, then it prints an error message, aborts, and returns an
+ * error code. Otherwise, returns 0. */
+int
+main(int argv, char **argc)
+{
+
+ int ectestTime = 0;
+ int ectestPrint = 0;
+ int i;
+ ECGroup *group = NULL;
+ ECCurveParams *params = NULL;
+ mp_err res;
+
+ /* read command-line arguments */
+ for (i = 1; i < argv; i++) {
+ if ((strcasecmp(argc[i], "time") == 0)
+ || (strcasecmp(argc[i], "-time") == 0)
+ || (strcasecmp(argc[i], "--time") == 0)) {
+ ectestTime = 1;
+ } else if ((strcasecmp(argc[i], "print") == 0)
+ || (strcasecmp(argc[i], "-print") == 0)
+ || (strcasecmp(argc[i], "--print") == 0)) {
+ ectestPrint = 1;
+ } else {
+ printUsage();
+ return 0;
+ }
+ }
+
+ /* generic arithmetic tests */
+ ECTEST_GENERIC_GFP("SECP-160R1", ECCurve_SECG_PRIME_160R1);
+
+ /* specific arithmetic tests */
+ ECTEST_NAMED_GFP("NIST-P192", ECCurve_NIST_P192);
+ ECTEST_NAMED_GFP("NIST-P224", ECCurve_NIST_P224);
+ ECTEST_NAMED_GFP("NIST-P256", ECCurve_NIST_P256);
+ ECTEST_NAMED_GFP("NIST-P384", ECCurve_NIST_P384);
+ ECTEST_NAMED_GFP("NIST-P521", ECCurve_NIST_P521);
+ ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v1", ECCurve_X9_62_PRIME_192V1);
+ ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v2", ECCurve_X9_62_PRIME_192V2);
+ ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v3", ECCurve_X9_62_PRIME_192V3);
+ ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v1", ECCurve_X9_62_PRIME_239V1);
+ ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v2", ECCurve_X9_62_PRIME_239V2);
+ ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v3", ECCurve_X9_62_PRIME_239V3);
+ ECTEST_NAMED_GFP("ANSI X9.62 PRIME256v1", ECCurve_X9_62_PRIME_256V1);
+ ECTEST_NAMED_GFP("SECP-112R1", ECCurve_SECG_PRIME_112R1);
+ ECTEST_NAMED_GFP("SECP-112R2", ECCurve_SECG_PRIME_112R2);
+ ECTEST_NAMED_GFP("SECP-128R1", ECCurve_SECG_PRIME_128R1);
+ ECTEST_NAMED_GFP("SECP-128R2", ECCurve_SECG_PRIME_128R2);
+ ECTEST_NAMED_GFP("SECP-160K1", ECCurve_SECG_PRIME_160K1);
+ ECTEST_NAMED_GFP("SECP-160R1", ECCurve_SECG_PRIME_160R1);
+ ECTEST_NAMED_GFP("SECP-160R2", ECCurve_SECG_PRIME_160R2);
+ ECTEST_NAMED_GFP("SECP-192K1", ECCurve_SECG_PRIME_192K1);
+ ECTEST_NAMED_GFP("SECP-192R1", ECCurve_SECG_PRIME_192R1);
+ ECTEST_NAMED_GFP("SECP-224K1", ECCurve_SECG_PRIME_224K1);
+ ECTEST_NAMED_GFP("SECP-224R1", ECCurve_SECG_PRIME_224R1);
+ ECTEST_NAMED_GFP("SECP-256K1", ECCurve_SECG_PRIME_256K1);
+ ECTEST_NAMED_GFP("SECP-256R1", ECCurve_SECG_PRIME_256R1);
+ ECTEST_NAMED_GFP("SECP-384R1", ECCurve_SECG_PRIME_384R1);
+ ECTEST_NAMED_GFP("SECP-521R1", ECCurve_SECG_PRIME_521R1);
+ ECTEST_NAMED_GFP("WTLS-6 (112)", ECCurve_WTLS_6);
+ ECTEST_NAMED_GFP("WTLS-7 (160)", ECCurve_WTLS_7);
+ ECTEST_NAMED_GFP("WTLS-8 (112)", ECCurve_WTLS_8);
+ ECTEST_NAMED_GFP("WTLS-9 (160)", ECCurve_WTLS_9);
+ ECTEST_NAMED_GFP("WTLS-12 (224)", ECCurve_WTLS_12);
+
+ CLEANUP:
+ EC_FreeCurveParams(params);
+ ECGroup_free(group);
+ if (res != MP_OKAY) {
+ printf("Error: exiting with error value %i\n", res);
+ }
+ return res;
+}