Commit 4f69172d authored by Bodo Möller's avatar Bodo Möller
Browse files

Completely remove mont2 stuff.

It does not appear to be faster than the current Montgomery code
except for very small moduli (somewhere between 192 and 224 bits
in a 64-bit Sun environment, and even less than 192 bits
on 32 bit systems).
parent eb272ac0
Loading
Loading
Loading
Loading

crypto/bn/bn_mont2.c

deleted100644 → 0
+0 −370
Original line number Diff line number Diff line
/*
 *
 *	bn_mont2.c
 *
 *	Montgomery Modular Arithmetic Functions.
 *
 *	Copyright (C) Lenka Fibikova 2000
 *
 *
 */


#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "bn_lcl.h"
#include "bn_mont2.h"

#define BN_mask_word(x, m) ((x->d[0]) & (m))

BN_MONTGOMERY *BN_mont_new()
	{
	BN_MONTGOMERY *ret;

	ret=(BN_MONTGOMERY *)malloc(sizeof(BN_MONTGOMERY));

	if (ret == NULL) return NULL;

	if ((ret->p = BN_new()) == NULL)
		{
		free(ret);
		return NULL;
		}

	return ret;
	}


void BN_mont_clear_free(BN_MONTGOMERY *mont)
	{
	if (mont == NULL) return;

	if (mont->p != NULL) BN_clear_free(mont->p);

	mont->p_num_bytes = 0;
	mont->R_num_bits = 0;
	mont->p_inv_b_neg = 0;
	}


int BN_to_mont(BIGNUM *x, BN_MONTGOMERY *mont, BN_CTX *ctx)
	{
	assert(x != NULL);

	assert(mont != NULL);
	assert(mont->p != NULL);

	assert(ctx != NULL);

	if (!BN_lshift(x, x, mont->R_num_bits)) return 0;
	if (!BN_mod(x, x, mont->p, ctx)) return 0;

	return 1;
	}


static BN_ULONG BN_mont_inv(BIGNUM *a, int e, BN_CTX *ctx)
/* y = a^{-1} (mod 2^e) for an odd number a */
	{
	BN_ULONG y, exp, mask;
	BIGNUM *x, *xy, *x_sh;
	int i;

	assert(a != NULL && ctx != NULL);
	assert(e <= BN_BITS2);
	assert(BN_is_odd(a));
	assert(!BN_is_zero(a) && !a->neg);


	y = 1;
	exp = 2;
	mask = 3;
	if((x = BN_dup(a)) == NULL) return 0;
	if (x->top > e/BN_BITS2)
		if(!BN_mask_bits(x, e)) return 0;

	BN_CTX_start(ctx);
	xy = BN_CTX_get(ctx);
	x_sh = BN_CTX_get(ctx);
	if (x_sh == NULL) goto err;

	if (BN_copy(xy, x) == NULL) goto err;
	if (!BN_lshift1(x_sh, x)) goto err;


	for (i = 2; i <= e; i++)
		{
		if (exp < BN_mask_word(xy, mask))
			{
			y = y + exp;
			if (!BN_add(xy, xy, x_sh)) goto err;
			}

		exp <<= 1;
		if (!BN_lshift1(x_sh, x_sh)) goto err;
		mask <<= 1;
		mask++;
		}


#ifdef TEST
	if (xy->d[0] != 1) goto err;
#endif

	if (x != NULL) BN_clear_free(x);
	BN_CTX_end(ctx);
	return y;


err:
	if (x != NULL) BN_clear_free(x);
	BN_CTX_end(ctx);
	return 0;
	}


int BN_mont_set(BIGNUM *p, BN_MONTGOMERY *mont, BN_CTX *ctx)
	{
	assert(p != NULL && ctx != NULL);
	assert(mont != NULL);
	assert(mont->p != NULL);
	assert(!BN_is_zero(p) && !p->neg);


	mont->p_num_bytes = p->top;
	mont->R_num_bits = (mont->p_num_bytes) * BN_BITS2;

	if (BN_copy(mont->p, p) == NULL);
	
	mont->p_inv_b_neg =  BN_mont_inv(p, BN_BITS2, ctx);
	if (!mont->p_inv_b_neg) return 0;
	mont->p_inv_b_neg = 0 - mont->p_inv_b_neg;

	return 1;
	}


#ifdef BN_LLONG
#define cpy_mul_add(r, b, a, w, c) { \
	BN_ULLONG t; \
	t = (BN_ULLONG)w * (a) + (b) + (c); \
	(r)= Lw(t); \
	(c)= Hw(t); \
	}

BN_ULONG BN_mul_add_rshift(BN_ULONG *r, BN_ULONG *a, int num, BN_ULONG w)
/* r = (r + a * w) >> BN_BITS2 */
	{
	BN_ULONG c = 0;

	mul_add(r[0], a[0], w, c);
	if (--num == 0) return c;
	a++;

	for (;;)
		{
		cpy_mul_add(r[0], r[1], a[0], w, c);
		if (--num == 0) break;
		cpy_mul_add(r[1], r[2], a[1], w, c);
		if (--num == 0) break;
		cpy_mul_add(r[2], r[3], a[2], w, c);
		if (--num == 0) break;
		cpy_mul_add(r[3], r[4], a[3], w, c);
		if (--num == 0) break;
		a += 4;
		r += 4;
		}
	
	return c;
	}
#else

#define cpy_mul_add(r, b, a, bl, bh, c) { \
	BN_ULONG l,h; \
 \
	h=(a); \
	l=LBITS(h); \
	h=HBITS(h); \
	mul64(l,h,(bl),(bh)); \
 \
	/* non-multiply part */ \
	l=(l+(c))&BN_MASK2; if (l < (c)) h++; \
	(c)=(b); \
	l=(l+(c))&BN_MASK2; if (l < (c)) h++; \
	(c)=h&BN_MASK2; \
	(r)=l; \
	}

static BN_ULONG BN_mul_add_rshift(BN_ULONG *r, BN_ULONG *a, int num, BN_ULONG w)
/* ret = (ret + a * w) << shift * BN_BITS2 */
	{
	BN_ULONG c = 0;
	BN_ULONG bl, bh;

	bl = LBITS(w);
	bh = HBITS(w);

	mul_add(r[0], a[0], bl, bh, c);
	if (--num == 0) return c;
	a++;

	for (;;)
		{
		cpy_mul_add(r[0], r[1], a[0], bl, bh, c);
		if (--num == 0) break;
		cpy_mul_add(r[1], r[2], a[1], bl, bh, c);
		if (--num == 0) break;
		cpy_mul_add(r[2], r[3], a[2], bl, bh, c);
		if (--num == 0) break;
		cpy_mul_add(r[3], r[4], a[3], bl, bh, c);
		if (--num == 0) break;
		a += 4;
		r += 4;
		}
	return c;
	}
#endif /* BN_LLONG */



int BN_mont_red(BIGNUM *y, BN_MONTGOMERY *mont)
/* yR^{-1} (mod p) */
	{
	BIGNUM *p;
	BN_ULONG c;
	int i, max;

	assert(y != NULL && mont != NULL);
	assert(mont->p != NULL);
	assert(BN_cmp(y, mont->p) < 0);
	assert(!y->neg);


	if (BN_is_zero(y)) return 1;

	p = mont->p;
	max = mont->p_num_bytes;

	if (bn_wexpand(y, max) == NULL) return 0;
	for (i = y->top; i < max; i++) y->d[i] = 0;
	y->top = max;

	/* r = [r + (y_0 * p') * p] / b */
	for (i = 0; i < max; i++)
		{
		c = BN_mul_add_rshift(y->d, p->d, max, ((y->d[0]) * mont->p_inv_b_neg) & BN_MASK2); 
		y->d[max - 1] = c;
		}

	while (y->d[y->top - 1] == 0) y->top--;

	if (BN_cmp(y, p) >= 0) 
		{
		if (!BN_sub(y, y, p)) return 0;
		}

	return 1;
	}


int BN_mont_mod_mul(BIGNUM *r_, BIGNUM *x, BIGNUM *y, BN_MONTGOMERY *mont, BN_CTX *ctx)
/* r = x * y mod p */
/* r != x && r! = y !!! */
	{
	BN_ULONG c;
	BIGNUM *p;
	int i, j, max;
	BIGNUM *r;

	assert(r_!= NULL && x != NULL  && y != NULL && mont != NULL);
	assert(mont->p != NULL);
	assert(BN_cmp(x, mont->p) < 0);
	assert(BN_cmp(y, mont->p) < 0);
	assert(!x->neg);
	assert(!y->neg);

	if (BN_is_zero(x) || BN_is_zero(y))
		{
		if (!BN_zero(r)) return 0;
		return 1;
		}

	if (r_ == x || r_ == y)
		{
		BN_CTX_start(ctx);
		r = BN_CTX_get(ctx);
		}
	else
		r = r_;

	p = mont->p;
	max = mont->p_num_bytes;

	/* for multiplication we need at most max + 2 words
		the last one --- max + 3 --- is only as a backstop
		for incorrect input 
	*/
	if (bn_wexpand(r, max + 3) == NULL) goto err;
	for (i = 0; i < max + 3; i++) r->d[i] = 0;
	r->top = max + 2;

	for (i = 0; i < x->top; i++)
		{
		/* r = r + (r_0 + x_i * y_0) * p' * p */
		c = bn_mul_add_words(r->d, p->d, max, \
			((r->d[0] + x->d[i] * y->d[0]) * mont->p_inv_b_neg) & BN_MASK2);
		if (c)
			{
			if (((r->d[max] += c) & BN_MASK2) < c)
				if (((r->d[max + 1] ++) & BN_MASK2) == 0) goto err;
			}
		
		/* r = (r + x_i * y) / b */
		c = BN_mul_add_rshift(r->d, y->d, y->top, x->d[i]); 
		for(j = y->top; j <= max + 1; j++) r->d[j - 1] = r->d[j];
		if (c)
			{
			if (((r->d[y->top - 1] += c) & BN_MASK2) < c)
				{
				j = y->top;
				while (((++ (r->d[j]) ) & BN_MASK2) == 0) 
					j++;
				if (j > max) goto err;
				}
			}
		r->d[max + 1] = 0;
		}

	for (i = x->top; i < max; i++)
		{
		/* r = (r + r_0 * p' * p) / b */
		c = BN_mul_add_rshift(r->d, p->d, max, ((r->d[0]) * mont->p_inv_b_neg) & BN_MASK2); 
		j = max - 1;
		r->d[j] = c + r->d[max];
		if (r->d[j++] < c) r->d[j] = r->d[++j] + 1;
		else r->d[j] = r->d[++j];
		r->d[max + 1] = 0;
		}

	while (r->d[r->top - 1] == 0) r->top--;

	if (BN_cmp(r, mont->p) >= 0) 
		{
		if (!BN_sub(r, r, mont->p)) goto err;
		}

	if (r != r_)
		{
		if (!BN_copy(r_, r)) goto err;
		BN_CTX_end(ctx);
		}

	return 1;

 err:
	if (r != r_)
		BN_CTX_end(ctx);
	return 0;
	}

crypto/bn/bn_mont2.h

deleted100644 → 0
+0 −36
Original line number Diff line number Diff line
/*
 *
 *	bn_mont2.h
 *
 *	Montgomery Modular Arithmetic Functions.
 *
 *	Copyright (C) Lenka Fibikova 2000
 *
 *
 */

#ifndef HEADER_MONT2_H
#define HEADER_MONT2_H

#define MONTGOMERY

#include <openssl/bn.h>

typedef struct bn_mont_st{
	int R_num_bits;
	int p_num_bytes;
	BIGNUM *p;
	BN_ULONG p_inv_b_neg;	/* p' = p^{-1} mod b; b = 2^BN_BITS */
} BN_MONTGOMERY;

#define BN_from_mont(x, mont) (BN_mont_red((x), (mont)))


BN_MONTGOMERY *BN_mont_new();
int BN_to_mont(BIGNUM *x, BN_MONTGOMERY *mont, BN_CTX *ctx); 
void BN_mont_clear_free(BN_MONTGOMERY *mont);
int BN_mont_set(BIGNUM *p, BN_MONTGOMERY *mont, BN_CTX *ctx);
int BN_mont_red(BIGNUM *y, BN_MONTGOMERY *mont);
int BN_mont_mod_mul(BIGNUM *r, BIGNUM *x, BIGNUM *y, BN_MONTGOMERY *mont, BN_CTX *);

#endif
+0 −5
Original line number Diff line number Diff line
@@ -175,10 +175,6 @@ void ERR_load_EC_strings(void);
/* Error codes for the EC functions. */

/* Function codes. */
#define EC_F_EC_GFP_MONT2_FIELD_DECODE			 143
#define EC_F_EC_GFP_MONT2_FIELD_ENCODE			 144
#define EC_F_EC_GFP_MONT2_FIELD_MUL			 145
#define EC_F_EC_GFP_MONT2_FIELD_SQR			 146
#define EC_F_EC_GFP_MONT_FIELD_DECODE			 133
#define EC_F_EC_GFP_MONT_FIELD_ENCODE			 134
#define EC_F_EC_GFP_MONT_FIELD_MUL			 131
@@ -221,7 +217,6 @@ void ERR_load_EC_strings(void);
#define EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP	 125
#define EC_F_EC_POINT_SET_JPROJECTIVE_COORDINATES_GFP	 126
#define EC_F_EC_POINT_SET_TO_INFINITY			 127
#define EC_F_GFP_MONT2_GROUP_SET_CURVE_GFP		 147
#define EC_F_GFP_MONT_GROUP_SET_CURVE_GFP		 135

/* Reason codes. */
+0 −5
Original line number Diff line number Diff line
@@ -66,10 +66,6 @@
#ifndef OPENSSL_NO_ERR
static ERR_STRING_DATA EC_str_functs[]=
	{
{ERR_PACK(0,EC_F_EC_GFP_MONT2_FIELD_DECODE,0),	"EC_GFP_MONT2_FIELD_DECODE"},
{ERR_PACK(0,EC_F_EC_GFP_MONT2_FIELD_ENCODE,0),	"EC_GFP_MONT2_FIELD_ENCODE"},
{ERR_PACK(0,EC_F_EC_GFP_MONT2_FIELD_MUL,0),	"EC_GFP_MONT2_FIELD_MUL"},
{ERR_PACK(0,EC_F_EC_GFP_MONT2_FIELD_SQR,0),	"EC_GFP_MONT2_FIELD_SQR"},
{ERR_PACK(0,EC_F_EC_GFP_MONT_FIELD_DECODE,0),	"ec_GFp_mont_field_decode"},
{ERR_PACK(0,EC_F_EC_GFP_MONT_FIELD_ENCODE,0),	"ec_GFp_mont_field_encode"},
{ERR_PACK(0,EC_F_EC_GFP_MONT_FIELD_MUL,0),	"ec_GFp_mont_field_mul"},
@@ -112,7 +108,6 @@ static ERR_STRING_DATA EC_str_functs[]=
{ERR_PACK(0,EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP,0),	"EC_POINT_set_compressed_coordinates_GFp"},
{ERR_PACK(0,EC_F_EC_POINT_SET_JPROJECTIVE_COORDINATES_GFP,0),	"EC_POINT_set_Jprojective_coordinates_GFp"},
{ERR_PACK(0,EC_F_EC_POINT_SET_TO_INFINITY,0),	"EC_POINT_set_to_infinity"},
{ERR_PACK(0,EC_F_GFP_MONT2_GROUP_SET_CURVE_GFP,0),	"GFP_MONT2_GROUP_SET_CURVE_GFP"},
{ERR_PACK(0,EC_F_GFP_MONT_GROUP_SET_CURVE_GFP,0),	"GFP_MONT_GROUP_SET_CURVE_GFP"},
{0,NULL}
	};

crypto/ec/ecp_mont2.c

deleted100644 → 0
+0 −283
Original line number Diff line number Diff line
/* unused */
/* crypto/ec/ecp_mont2.c */
/* ====================================================================
 * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
 *
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    openssl-core@openssl.org.
 *
 * 5. Products derived from this software may not be called "OpenSSL"
 *    nor may "OpenSSL" appear in their names without prior written
 *    permission of the OpenSSL Project.
 *
 * 6. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
 *
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 *
 * This product includes cryptographic software written by Eric Young
 * (eay@cryptsoft.com).  This product includes software written by Tim
 * Hudson (tjh@cryptsoft.com).
 *
 */

#define NDEBUG

#include <openssl/err.h>

#include "ec_lcl.h"

#include "../bn/bn_mont2.c"

int ec_GFp_mont2_group_init(EC_GROUP *);
int ec_GFp_mont2_group_set_curve_GFp(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
void ec_GFp_mont2_group_finish(EC_GROUP *);
void ec_GFp_mont2_group_clear_finish(EC_GROUP *);
/* int ec_GFp_mont2_group_copy(EC_GROUP *, const EC_GROUP *); */
int ec_GFp_mont2_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
int ec_GFp_mont2_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
int ec_GFp_mont2_field_encode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
int ec_GFp_mont2_field_decode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
int ec_GFp_mont2_field_set_to_one(const EC_GROUP *, BIGNUM *r, BN_CTX *);

const EC_METHOD *EC_GFp_mont2_method(void)
	{
	static const EC_METHOD ret = {
		ec_GFp_mont2_group_init,
		ec_GFp_mont2_group_finish,
		ec_GFp_mont2_group_clear_finish,
		0 /* ec_GFp_mont2_group_copy */,
		ec_GFp_mont2_group_set_curve_GFp,
		ec_GFp_simple_group_get_curve_GFp,
		ec_GFp_simple_group_set_generator,
		ec_GFp_simple_group_get0_generator,
		ec_GFp_simple_group_get_order,
		ec_GFp_simple_group_get_cofactor,
		ec_GFp_simple_point_init,
		ec_GFp_simple_point_finish,
		ec_GFp_simple_point_clear_finish,
		ec_GFp_simple_point_copy,
		ec_GFp_simple_point_set_to_infinity,
		ec_GFp_simple_set_Jprojective_coordinates_GFp,
		ec_GFp_simple_get_Jprojective_coordinates_GFp,
		ec_GFp_simple_point_set_affine_coordinates_GFp,
		ec_GFp_simple_point_get_affine_coordinates_GFp,
		ec_GFp_simple_set_compressed_coordinates_GFp,
		ec_GFp_simple_point2oct,
		ec_GFp_simple_oct2point,
		ec_GFp_simple_add,
		ec_GFp_simple_dbl,
		ec_GFp_simple_invert,
		ec_GFp_simple_is_at_infinity,
		ec_GFp_simple_is_on_curve,
		ec_GFp_simple_cmp,
		ec_GFp_simple_make_affine,
		ec_GFp_simple_points_make_affine,
		ec_GFp_mont2_field_mul,
		ec_GFp_mont2_field_sqr,
		ec_GFp_mont2_field_encode,
		ec_GFp_mont2_field_decode,
		ec_GFp_mont2_field_set_to_one };

	return &ret;
	}


int ec_GFp_mont2_group_init(EC_GROUP *group)
	{
	int ok;

	ok = ec_GFp_simple_group_init(group);
	group->field_data1 = NULL;
	group->field_data2 = NULL;
	return ok;
	}


int ec_GFp_mont2_group_set_curve_GFp(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
	{
	BN_CTX *new_ctx = NULL;
	BN_MONTGOMERY *mont = NULL;
	BIGNUM *one = NULL;
	int ret = 0;

	if (group->field_data1 != NULL)
		{
		BN_mont_clear_free(group->field_data1);
		group->field_data1 = NULL;
		}
	if (group->field_data2 != NULL)
		{
		BN_free(group->field_data2);
		group->field_data2 = NULL;
		}
	
	if (ctx == NULL)
		{
		ctx = new_ctx = BN_CTX_new();
		if (ctx == NULL)
			return 0;
		}

	mont = BN_mont_new();
	if (mont == NULL) goto err;
	if (!BN_mont_set(p, mont, ctx))
		{
		ECerr(EC_F_GFP_MONT2_GROUP_SET_CURVE_GFP, ERR_R_BN_LIB);
		goto err;
		}
	one = BN_new();
	if (one == NULL) goto err;
	if (!BN_one(one)) goto err;
	if (!BN_to_mont(one, mont, ctx)) goto err;

	group->field_data1 = mont;
	mont = NULL;
	group->field_data2 = one;
	one = NULL;

	ret = ec_GFp_simple_group_set_curve_GFp(group, p, a, b, ctx);

	if (!ret)
		{
		BN_mont_clear_free(group->field_data1);
		group->field_data1 = NULL;
		BN_free(group->field_data2);
		group->field_data2 = NULL;
		}

 err:
	if (new_ctx != NULL)
		BN_CTX_free(new_ctx);
	if (mont != NULL)
		BN_mont_clear_free(mont);
	return ret;
	}


void ec_GFp_mont2_group_finish(EC_GROUP *group)
	{
	if (group->field_data1 != NULL)
		{
		BN_mont_clear_free(group->field_data1);
		group->field_data1 = NULL;
		}
	if (group->field_data2 != NULL)
		{
		BN_free(group->field_data2);
		group->field_data2 = NULL;
		}
	ec_GFp_simple_group_finish(group);
	}


void ec_GFp_mont2_group_clear_finish(EC_GROUP *group)
	{
	if (group->field_data1 != NULL)
		{
		BN_mont_clear_free(group->field_data1);
		group->field_data1 = NULL;
		}
	if (group->field_data2 != NULL)
		{
		BN_clear_free(group->field_data2);
		group->field_data2 = NULL;
		}
	ec_GFp_simple_group_clear_finish(group);
	}


int ec_GFp_mont2_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
	{
	if (group->field_data1 == NULL)
		{
		ECerr(EC_F_EC_GFP_MONT2_FIELD_MUL, EC_R_NOT_INITIALIZED);
		return 0;
		}

	return BN_mont_mod_mul(r, a, b, group->field_data1, ctx);
	}


int ec_GFp_mont2_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
	{
	if (group->field_data1 == NULL)
		{
		ECerr(EC_F_EC_GFP_MONT2_FIELD_SQR, EC_R_NOT_INITIALIZED);
		return 0;
		}

	return BN_mont_mod_mul(r, a, a, group->field_data1, ctx);
	}


int ec_GFp_mont2_field_encode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
	{
	if (group->field_data1 == NULL)
		{
		ECerr(EC_F_EC_GFP_MONT2_FIELD_ENCODE, EC_R_NOT_INITIALIZED);
		return 0;
		}

	if (!BN_copy(r, a)) return 0;
	return BN_to_mont(r, (BN_MONTGOMERY *)group->field_data1, ctx);
	}


int ec_GFp_mont2_field_decode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
	{
	if (group->field_data1 == NULL)
		{
		ECerr(EC_F_EC_GFP_MONT2_FIELD_DECODE, EC_R_NOT_INITIALIZED);
		return 0;
		}

	if (!BN_copy(r, a)) return 0;
	return BN_mont_red(r, (BN_MONTGOMERY *)group->field_data1);
	}


int ec_GFp_mont2_field_set_to_one(const EC_GROUP *group, BIGNUM *r, BN_CTX *ctx)
	{
	if (group->field_data2 == NULL)
		{
		ECerr(EC_F_EC_GFP_MONT2_FIELD_DECODE, EC_R_NOT_INITIALIZED);
		return 0;
		}

	if (!BN_copy(r, group->field_data2)) return 0;
	return 1;
	}