4272N/A/*
4272N/A * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
4272N/A * Use is subject to license terms.
4272N/A *
4272N/A * This library is free software; you can redistribute it and/or
4272N/A * modify it under the terms of the GNU Lesser General Public
4272N/A * License as published by the Free Software Foundation; either
4272N/A * version 2.1 of the License, or (at your option) any later version.
1674N/A *
4272N/A * This library is distributed in the hope that it will be useful,
4272N/A * but WITHOUT ANY WARRANTY; without even the implied warranty of
4272N/A * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4272N/A * Lesser General Public License for more details.
1674N/A *
4272N/A * You should have received a copy of the GNU Lesser General Public License
4272N/A * along with this library; if not, write to the Free Software Foundation,
4272N/A * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1674N/A *
4272N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
4272N/A * or visit www.oracle.com if you need additional information or have any
4272N/A * questions.
4272N/A */
4272N/A
4272N/A/* *********************************************************************
1674N/A *
1674N/A * The Original Code is the elliptic curve math library for prime field curves.
1674N/A *
1674N/A * The Initial Developer of the Original Code is
1674N/A * Sun Microsystems, Inc.
1674N/A * Portions created by the Initial Developer are Copyright (C) 2003
1674N/A * the Initial Developer. All Rights Reserved.
1674N/A *
1674N/A * Contributor(s):
1674N/A * Douglas Stebila <douglas@stebila.ca>
1674N/A *
1674N/A *********************************************************************** */
1674N/A
1674N/A#include "ecp.h"
1674N/A#include "mpi.h"
1674N/A#include "mplogic.h"
1674N/A#include "mpi-priv.h"
1674N/A#ifndef _KERNEL
1674N/A#include <stdlib.h>
1674N/A#endif
1674N/A
1674N/A#define ECP521_DIGITS ECL_CURVE_DIGITS(521)
1674N/A
1674N/A/* Fast modular reduction for p521 = 2^521 - 1. a can be r. Uses
1674N/A * algorithm 2.31 from Hankerson, Menezes, Vanstone. Guide to
1674N/A * Elliptic Curve Cryptography. */
1674N/Amp_err
1674N/Aec_GFp_nistp521_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
1674N/A{
1674N/A mp_err res = MP_OKAY;
1674N/A int a_bits = mpl_significant_bits(a);
3488N/A unsigned int i;
1674N/A
1674N/A /* m1, m2 are statically-allocated mp_int of exactly the size we need */
1674N/A mp_int m1;
1674N/A
1674N/A mp_digit s1[ECP521_DIGITS] = { 0 };
1674N/A
1674N/A MP_SIGN(&m1) = MP_ZPOS;
1674N/A MP_ALLOC(&m1) = ECP521_DIGITS;
1674N/A MP_USED(&m1) = ECP521_DIGITS;
1674N/A MP_DIGITS(&m1) = s1;
1674N/A
1674N/A if (a_bits < 521) {
1674N/A if (a==r) return MP_OKAY;
1674N/A return mp_copy(a, r);
1674N/A }
1674N/A /* for polynomials larger than twice the field size or polynomials
1674N/A * not using all words, use regular reduction */
1674N/A if (a_bits > (521*2)) {
1674N/A MP_CHECKOK(mp_mod(a, &meth->irr, r));
1674N/A } else {
1674N/A#define FIRST_DIGIT (ECP521_DIGITS-1)
1674N/A for (i = FIRST_DIGIT; i < MP_USED(a)-1; i++) {
1674N/A s1[i-FIRST_DIGIT] = (MP_DIGIT(a, i) >> 9)
1674N/A | (MP_DIGIT(a, 1+i) << (MP_DIGIT_BIT-9));
1674N/A }
1674N/A s1[i-FIRST_DIGIT] = MP_DIGIT(a, i) >> 9;
1674N/A
1674N/A if ( a != r ) {
1674N/A MP_CHECKOK(s_mp_pad(r,ECP521_DIGITS));
1674N/A for (i = 0; i < ECP521_DIGITS; i++) {
1674N/A MP_DIGIT(r,i) = MP_DIGIT(a, i);
1674N/A }
1674N/A }
1674N/A MP_USED(r) = ECP521_DIGITS;
1674N/A MP_DIGIT(r,FIRST_DIGIT) &= 0x1FF;
1674N/A
1674N/A MP_CHECKOK(s_mp_add(r, &m1));
1674N/A if (MP_DIGIT(r, FIRST_DIGIT) & 0x200) {
1674N/A MP_CHECKOK(s_mp_add_d(r,1));
1674N/A MP_DIGIT(r,FIRST_DIGIT) &= 0x1FF;
1674N/A }
1674N/A s_mp_clamp(r);
1674N/A }
1674N/A
1674N/A CLEANUP:
1674N/A return res;
1674N/A}
1674N/A
1674N/A/* Compute the square of polynomial a, reduce modulo p521. Store the
1674N/A * result in r. r could be a. Uses optimized modular reduction for p521.
1674N/A */
1674N/Amp_err
1674N/Aec_GFp_nistp521_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
1674N/A{
1674N/A mp_err res = MP_OKAY;
1674N/A
1674N/A MP_CHECKOK(mp_sqr(a, r));
1674N/A MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth));
1674N/A CLEANUP:
1674N/A return res;
1674N/A}
1674N/A
1674N/A/* Compute the product of two polynomials a and b, reduce modulo p521.
1674N/A * Store the result in r. r could be a or b; a could be b. Uses
1674N/A * optimized modular reduction for p521. */
1674N/Amp_err
1674N/Aec_GFp_nistp521_mul(const mp_int *a, const mp_int *b, mp_int *r,
1674N/A const GFMethod *meth)
1674N/A{
1674N/A mp_err res = MP_OKAY;
1674N/A
1674N/A MP_CHECKOK(mp_mul(a, b, r));
1674N/A MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth));
1674N/A CLEANUP:
1674N/A return res;
1674N/A}
1674N/A
1674N/A/* Divides two field elements. If a is NULL, then returns the inverse of
1674N/A * b. */
1674N/Amp_err
1674N/Aec_GFp_nistp521_div(const mp_int *a, const mp_int *b, mp_int *r,
1674N/A const GFMethod *meth)
1674N/A{
1674N/A mp_err res = MP_OKAY;
1674N/A mp_int t;
1674N/A
1674N/A /* If a is NULL, then return the inverse of b, otherwise return a/b. */
1674N/A if (a == NULL) {
1674N/A return mp_invmod(b, &meth->irr, r);
1674N/A } else {
1674N/A /* MPI doesn't support divmod, so we implement it using invmod and
1674N/A * mulmod. */
1674N/A MP_CHECKOK(mp_init(&t, FLAG(b)));
1674N/A MP_CHECKOK(mp_invmod(b, &meth->irr, &t));
1674N/A MP_CHECKOK(mp_mul(a, &t, r));
1674N/A MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth));
1674N/A CLEANUP:
1674N/A mp_clear(&t);
1674N/A return res;
1674N/A }
1674N/A}
1674N/A
1674N/A/* Wire in fast field arithmetic and precomputation of base point for
1674N/A * named curves. */
1674N/Amp_err
1674N/Aec_group_set_gfp521(ECGroup *group, ECCurveName name)
1674N/A{
1674N/A if (name == ECCurve_NIST_P521) {
1674N/A group->meth->field_mod = &ec_GFp_nistp521_mod;
1674N/A group->meth->field_mul = &ec_GFp_nistp521_mul;
1674N/A group->meth->field_sqr = &ec_GFp_nistp521_sqr;
1674N/A group->meth->field_div = &ec_GFp_nistp521_div;
1674N/A }
1674N/A return MP_OKAY;
1674N/A}