Back to index

lightning-sunbird  0.9+nobinonly
ecp_521.c
Go to the documentation of this file.
00001 /* 
00002  * ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the elliptic curve math library for prime field curves.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Sun Microsystems, Inc.
00019  * Portions created by the Initial Developer are Copyright (C) 2003
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Douglas Stebila <douglas@stebila.ca>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "ecp.h"
00040 #include "mpi.h"
00041 #include "mplogic.h"
00042 #include "mpi-priv.h"
00043 #include <stdlib.h>
00044 
00045 #define ECP521_DIGITS ECL_CURVE_DIGITS(521)
00046 
00047 /* Fast modular reduction for p521 = 2^521 - 1.  a can be r. Uses
00048  * algorithm 2.31 from Hankerson, Menezes, Vanstone. Guide to 
00049  * Elliptic Curve Cryptography. */
00050 mp_err
00051 ec_GFp_nistp521_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
00052 {
00053        mp_err res = MP_OKAY;
00054        int a_bits = mpl_significant_bits(a);
00055        int i;
00056 
00057        /* m1, m2 are statically-allocated mp_int of exactly the size we need */
00058        mp_int m1;
00059 
00060        mp_digit s1[ECP521_DIGITS] = { 0 };
00061 
00062        MP_SIGN(&m1) = MP_ZPOS;
00063        MP_ALLOC(&m1) = ECP521_DIGITS;
00064        MP_USED(&m1) = ECP521_DIGITS;
00065        MP_DIGITS(&m1) = s1;
00066 
00067        if (a_bits < 521) {
00068               if (a==r) return MP_OKAY;
00069               return mp_copy(a, r);
00070        }
00071        /* for polynomials larger than twice the field size or polynomials 
00072         * not using all words, use regular reduction */
00073        if (a_bits > (521*2)) {
00074               MP_CHECKOK(mp_mod(a, &meth->irr, r));
00075        } else {
00076 #define FIRST_DIGIT (ECP521_DIGITS-1)
00077               for (i = FIRST_DIGIT; i < MP_USED(a)-1; i++) {
00078                      s1[i-FIRST_DIGIT] = (MP_DIGIT(a, i) >> 9) 
00079                             | (MP_DIGIT(a, 1+i) << (MP_DIGIT_BIT-9));
00080               }
00081               s1[i-FIRST_DIGIT] = MP_DIGIT(a, i) >> 9;
00082 
00083               if ( a != r ) {
00084                      MP_CHECKOK(s_mp_pad(r,ECP521_DIGITS));
00085                      for (i = 0; i < ECP521_DIGITS; i++) {
00086                             MP_DIGIT(r,i) = MP_DIGIT(a, i);
00087                      }
00088               }
00089               MP_USED(r) = ECP521_DIGITS;
00090               MP_DIGIT(r,FIRST_DIGIT) &=  0x1FF;
00091 
00092               MP_CHECKOK(s_mp_add(r, &m1));
00093               if (MP_DIGIT(r, FIRST_DIGIT) & 0x200) {
00094                      MP_CHECKOK(s_mp_add_d(r,1));
00095                      MP_DIGIT(r,FIRST_DIGIT) &=  0x1FF;
00096               }
00097               s_mp_clamp(r);
00098        }
00099 
00100   CLEANUP:
00101        return res;
00102 }
00103 
00104 /* Compute the square of polynomial a, reduce modulo p521. Store the
00105  * result in r.  r could be a.  Uses optimized modular reduction for p521. 
00106  */
00107 mp_err
00108 ec_GFp_nistp521_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
00109 {
00110        mp_err res = MP_OKAY;
00111 
00112        MP_CHECKOK(mp_sqr(a, r));
00113        MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth));
00114   CLEANUP:
00115        return res;
00116 }
00117 
00118 /* Compute the product of two polynomials a and b, reduce modulo p521.
00119  * Store the result in r.  r could be a or b; a could be b.  Uses
00120  * optimized modular reduction for p521. */
00121 mp_err
00122 ec_GFp_nistp521_mul(const mp_int *a, const mp_int *b, mp_int *r,
00123                                    const GFMethod *meth)
00124 {
00125        mp_err res = MP_OKAY;
00126 
00127        MP_CHECKOK(mp_mul(a, b, r));
00128        MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth));
00129   CLEANUP:
00130        return res;
00131 }
00132 
00133 /* Divides two field elements. If a is NULL, then returns the inverse of
00134  * b. */
00135 mp_err
00136 ec_GFp_nistp521_div(const mp_int *a, const mp_int *b, mp_int *r,
00137                  const GFMethod *meth)
00138 {
00139        mp_err res = MP_OKAY;
00140        mp_int t;
00141 
00142        /* If a is NULL, then return the inverse of b, otherwise return a/b. */
00143        if (a == NULL) {
00144               return mp_invmod(b, &meth->irr, r);
00145        } else {
00146               /* MPI doesn't support divmod, so we implement it using invmod and 
00147                * mulmod. */
00148               MP_CHECKOK(mp_init(&t));
00149               MP_CHECKOK(mp_invmod(b, &meth->irr, &t));
00150               MP_CHECKOK(mp_mul(a, &t, r));
00151               MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth));
00152          CLEANUP:
00153               mp_clear(&t);
00154               return res;
00155        }
00156 }
00157 
00158 /* Wire in fast field arithmetic and precomputation of base point for
00159  * named curves. */
00160 mp_err
00161 ec_group_set_gfp521(ECGroup *group, ECCurveName name)
00162 {
00163        if (name == ECCurve_NIST_P521) {
00164               group->meth->field_mod = &ec_GFp_nistp521_mod;
00165               group->meth->field_mul = &ec_GFp_nistp521_mul;
00166               group->meth->field_sqr = &ec_GFp_nistp521_sqr;
00167               group->meth->field_div = &ec_GFp_nistp521_div;
00168        }
00169        return MP_OKAY;
00170 }