1160814Ssimon/* crypto/bn/bn_gf2m.c */
2160814Ssimon/* ====================================================================
3160814Ssimon * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
4160814Ssimon *
5160814Ssimon * The Elliptic Curve Public-Key Crypto Library (ECC Code) included
6160814Ssimon * herein is developed by SUN MICROSYSTEMS, INC., and is contributed
7160814Ssimon * to the OpenSSL project.
8160814Ssimon *
9160814Ssimon * The ECC Code is licensed pursuant to the OpenSSL open source
10160814Ssimon * license provided below.
11160814Ssimon *
12160814Ssimon * In addition, Sun covenants to all licensees who provide a reciprocal
13160814Ssimon * covenant with respect to their own patents if any, not to sue under
14160814Ssimon * current and future patent claims necessarily infringed by the making,
15160814Ssimon * using, practicing, selling, offering for sale and/or otherwise
16160814Ssimon * disposing of the ECC Code as delivered hereunder (or portions thereof),
17160814Ssimon * provided that such covenant shall not apply:
18160814Ssimon *  1) for code that a licensee deletes from the ECC Code;
19160814Ssimon *  2) separates from the ECC Code; or
20160814Ssimon *  3) for infringements caused by:
21160814Ssimon *       i) the modification of the ECC Code or
22160814Ssimon *      ii) the combination of the ECC Code with other software or
23160814Ssimon *          devices where such combination causes the infringement.
24160814Ssimon *
25160814Ssimon * The software is originally written by Sheueling Chang Shantz and
26160814Ssimon * Douglas Stebila of Sun Microsystems Laboratories.
27160814Ssimon *
28160814Ssimon */
29160814Ssimon
30160814Ssimon/* NOTE: This file is licensed pursuant to the OpenSSL license below
31160814Ssimon * and may be modified; but after modifications, the above covenant
32160814Ssimon * may no longer apply!  In such cases, the corresponding paragraph
33160814Ssimon * ["In addition, Sun covenants ... causes the infringement."] and
34160814Ssimon * this note can be edited out; but please keep the Sun copyright
35160814Ssimon * notice and attribution. */
36160814Ssimon
37160814Ssimon/* ====================================================================
38160814Ssimon * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
39160814Ssimon *
40160814Ssimon * Redistribution and use in source and binary forms, with or without
41160814Ssimon * modification, are permitted provided that the following conditions
42160814Ssimon * are met:
43160814Ssimon *
44160814Ssimon * 1. Redistributions of source code must retain the above copyright
45160814Ssimon *    notice, this list of conditions and the following disclaimer.
46160814Ssimon *
47160814Ssimon * 2. Redistributions in binary form must reproduce the above copyright
48160814Ssimon *    notice, this list of conditions and the following disclaimer in
49160814Ssimon *    the documentation and/or other materials provided with the
50160814Ssimon *    distribution.
51160814Ssimon *
52160814Ssimon * 3. All advertising materials mentioning features or use of this
53160814Ssimon *    software must display the following acknowledgment:
54160814Ssimon *    "This product includes software developed by the OpenSSL Project
55160814Ssimon *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
56160814Ssimon *
57160814Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
58160814Ssimon *    endorse or promote products derived from this software without
59160814Ssimon *    prior written permission. For written permission, please contact
60160814Ssimon *    openssl-core@openssl.org.
61160814Ssimon *
62160814Ssimon * 5. Products derived from this software may not be called "OpenSSL"
63160814Ssimon *    nor may "OpenSSL" appear in their names without prior written
64160814Ssimon *    permission of the OpenSSL Project.
65160814Ssimon *
66160814Ssimon * 6. Redistributions of any form whatsoever must retain the following
67160814Ssimon *    acknowledgment:
68160814Ssimon *    "This product includes software developed by the OpenSSL Project
69160814Ssimon *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
70160814Ssimon *
71160814Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
72160814Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
73160814Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
74160814Ssimon * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
75160814Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
76160814Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
77160814Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
78160814Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
79160814Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
80160814Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
81160814Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
82160814Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE.
83160814Ssimon * ====================================================================
84160814Ssimon *
85160814Ssimon * This product includes cryptographic software written by Eric Young
86160814Ssimon * (eay@cryptsoft.com).  This product includes software written by Tim
87160814Ssimon * Hudson (tjh@cryptsoft.com).
88160814Ssimon *
89160814Ssimon */
90160814Ssimon
91160814Ssimon#include <assert.h>
92160814Ssimon#include <limits.h>
93160814Ssimon#include <stdio.h>
94160814Ssimon#include "cryptlib.h"
95160814Ssimon#include "bn_lcl.h"
96160814Ssimon
97238405Sjkim#ifndef OPENSSL_NO_EC2M
98238405Sjkim
99160814Ssimon/* Maximum number of iterations before BN_GF2m_mod_solve_quad_arr should fail. */
100160814Ssimon#define MAX_ITERATIONS 50
101160814Ssimon
102160814Ssimonstatic const BN_ULONG SQR_tb[16] =
103160814Ssimon  {     0,     1,     4,     5,    16,    17,    20,    21,
104160814Ssimon       64,    65,    68,    69,    80,    81,    84,    85 };
105160814Ssimon/* Platform-specific macros to accelerate squaring. */
106160814Ssimon#if defined(SIXTY_FOUR_BIT) || defined(SIXTY_FOUR_BIT_LONG)
107160814Ssimon#define SQR1(w) \
108160814Ssimon    SQR_tb[(w) >> 60 & 0xF] << 56 | SQR_tb[(w) >> 56 & 0xF] << 48 | \
109160814Ssimon    SQR_tb[(w) >> 52 & 0xF] << 40 | SQR_tb[(w) >> 48 & 0xF] << 32 | \
110160814Ssimon    SQR_tb[(w) >> 44 & 0xF] << 24 | SQR_tb[(w) >> 40 & 0xF] << 16 | \
111160814Ssimon    SQR_tb[(w) >> 36 & 0xF] <<  8 | SQR_tb[(w) >> 32 & 0xF]
112160814Ssimon#define SQR0(w) \
113160814Ssimon    SQR_tb[(w) >> 28 & 0xF] << 56 | SQR_tb[(w) >> 24 & 0xF] << 48 | \
114160814Ssimon    SQR_tb[(w) >> 20 & 0xF] << 40 | SQR_tb[(w) >> 16 & 0xF] << 32 | \
115160814Ssimon    SQR_tb[(w) >> 12 & 0xF] << 24 | SQR_tb[(w) >>  8 & 0xF] << 16 | \
116160814Ssimon    SQR_tb[(w) >>  4 & 0xF] <<  8 | SQR_tb[(w)       & 0xF]
117160814Ssimon#endif
118160814Ssimon#ifdef THIRTY_TWO_BIT
119160814Ssimon#define SQR1(w) \
120160814Ssimon    SQR_tb[(w) >> 28 & 0xF] << 24 | SQR_tb[(w) >> 24 & 0xF] << 16 | \
121160814Ssimon    SQR_tb[(w) >> 20 & 0xF] <<  8 | SQR_tb[(w) >> 16 & 0xF]
122160814Ssimon#define SQR0(w) \
123160814Ssimon    SQR_tb[(w) >> 12 & 0xF] << 24 | SQR_tb[(w) >>  8 & 0xF] << 16 | \
124160814Ssimon    SQR_tb[(w) >>  4 & 0xF] <<  8 | SQR_tb[(w)       & 0xF]
125160814Ssimon#endif
126160814Ssimon
127238405Sjkim#if !defined(OPENSSL_BN_ASM_GF2m)
128160814Ssimon/* Product of two polynomials a, b each with degree < BN_BITS2 - 1,
129160814Ssimon * result is a polynomial r with degree < 2 * BN_BITS - 1
130160814Ssimon * The caller MUST ensure that the variables have the right amount
131160814Ssimon * of space allocated.
132160814Ssimon */
133160814Ssimon#ifdef THIRTY_TWO_BIT
134160814Ssimonstatic void bn_GF2m_mul_1x1(BN_ULONG *r1, BN_ULONG *r0, const BN_ULONG a, const BN_ULONG b)
135160814Ssimon	{
136160814Ssimon	register BN_ULONG h, l, s;
137160814Ssimon	BN_ULONG tab[8], top2b = a >> 30;
138160814Ssimon	register BN_ULONG a1, a2, a4;
139160814Ssimon
140160814Ssimon	a1 = a & (0x3FFFFFFF); a2 = a1 << 1; a4 = a2 << 1;
141160814Ssimon
142160814Ssimon	tab[0] =  0; tab[1] = a1;    tab[2] = a2;    tab[3] = a1^a2;
143160814Ssimon	tab[4] = a4; tab[5] = a1^a4; tab[6] = a2^a4; tab[7] = a1^a2^a4;
144160814Ssimon
145160814Ssimon	s = tab[b       & 0x7]; l  = s;
146160814Ssimon	s = tab[b >>  3 & 0x7]; l ^= s <<  3; h  = s >> 29;
147160814Ssimon	s = tab[b >>  6 & 0x7]; l ^= s <<  6; h ^= s >> 26;
148160814Ssimon	s = tab[b >>  9 & 0x7]; l ^= s <<  9; h ^= s >> 23;
149160814Ssimon	s = tab[b >> 12 & 0x7]; l ^= s << 12; h ^= s >> 20;
150160814Ssimon	s = tab[b >> 15 & 0x7]; l ^= s << 15; h ^= s >> 17;
151160814Ssimon	s = tab[b >> 18 & 0x7]; l ^= s << 18; h ^= s >> 14;
152160814Ssimon	s = tab[b >> 21 & 0x7]; l ^= s << 21; h ^= s >> 11;
153160814Ssimon	s = tab[b >> 24 & 0x7]; l ^= s << 24; h ^= s >>  8;
154160814Ssimon	s = tab[b >> 27 & 0x7]; l ^= s << 27; h ^= s >>  5;
155160814Ssimon	s = tab[b >> 30      ]; l ^= s << 30; h ^= s >>  2;
156160814Ssimon
157160814Ssimon	/* compensate for the top two bits of a */
158160814Ssimon
159160814Ssimon	if (top2b & 01) { l ^= b << 30; h ^= b >> 2; }
160160814Ssimon	if (top2b & 02) { l ^= b << 31; h ^= b >> 1; }
161160814Ssimon
162160814Ssimon	*r1 = h; *r0 = l;
163160814Ssimon	}
164160814Ssimon#endif
165160814Ssimon#if defined(SIXTY_FOUR_BIT) || defined(SIXTY_FOUR_BIT_LONG)
166160814Ssimonstatic void bn_GF2m_mul_1x1(BN_ULONG *r1, BN_ULONG *r0, const BN_ULONG a, const BN_ULONG b)
167160814Ssimon	{
168160814Ssimon	register BN_ULONG h, l, s;
169160814Ssimon	BN_ULONG tab[16], top3b = a >> 61;
170160814Ssimon	register BN_ULONG a1, a2, a4, a8;
171160814Ssimon
172160814Ssimon	a1 = a & (0x1FFFFFFFFFFFFFFFULL); a2 = a1 << 1; a4 = a2 << 1; a8 = a4 << 1;
173160814Ssimon
174160814Ssimon	tab[ 0] = 0;     tab[ 1] = a1;       tab[ 2] = a2;       tab[ 3] = a1^a2;
175160814Ssimon	tab[ 4] = a4;    tab[ 5] = a1^a4;    tab[ 6] = a2^a4;    tab[ 7] = a1^a2^a4;
176160814Ssimon	tab[ 8] = a8;    tab[ 9] = a1^a8;    tab[10] = a2^a8;    tab[11] = a1^a2^a8;
177160814Ssimon	tab[12] = a4^a8; tab[13] = a1^a4^a8; tab[14] = a2^a4^a8; tab[15] = a1^a2^a4^a8;
178160814Ssimon
179160814Ssimon	s = tab[b       & 0xF]; l  = s;
180160814Ssimon	s = tab[b >>  4 & 0xF]; l ^= s <<  4; h  = s >> 60;
181160814Ssimon	s = tab[b >>  8 & 0xF]; l ^= s <<  8; h ^= s >> 56;
182160814Ssimon	s = tab[b >> 12 & 0xF]; l ^= s << 12; h ^= s >> 52;
183160814Ssimon	s = tab[b >> 16 & 0xF]; l ^= s << 16; h ^= s >> 48;
184160814Ssimon	s = tab[b >> 20 & 0xF]; l ^= s << 20; h ^= s >> 44;
185160814Ssimon	s = tab[b >> 24 & 0xF]; l ^= s << 24; h ^= s >> 40;
186160814Ssimon	s = tab[b >> 28 & 0xF]; l ^= s << 28; h ^= s >> 36;
187160814Ssimon	s = tab[b >> 32 & 0xF]; l ^= s << 32; h ^= s >> 32;
188160814Ssimon	s = tab[b >> 36 & 0xF]; l ^= s << 36; h ^= s >> 28;
189160814Ssimon	s = tab[b >> 40 & 0xF]; l ^= s << 40; h ^= s >> 24;
190160814Ssimon	s = tab[b >> 44 & 0xF]; l ^= s << 44; h ^= s >> 20;
191160814Ssimon	s = tab[b >> 48 & 0xF]; l ^= s << 48; h ^= s >> 16;
192160814Ssimon	s = tab[b >> 52 & 0xF]; l ^= s << 52; h ^= s >> 12;
193160814Ssimon	s = tab[b >> 56 & 0xF]; l ^= s << 56; h ^= s >>  8;
194160814Ssimon	s = tab[b >> 60      ]; l ^= s << 60; h ^= s >>  4;
195160814Ssimon
196160814Ssimon	/* compensate for the top three bits of a */
197160814Ssimon
198160814Ssimon	if (top3b & 01) { l ^= b << 61; h ^= b >> 3; }
199160814Ssimon	if (top3b & 02) { l ^= b << 62; h ^= b >> 2; }
200160814Ssimon	if (top3b & 04) { l ^= b << 63; h ^= b >> 1; }
201160814Ssimon
202160814Ssimon	*r1 = h; *r0 = l;
203160814Ssimon	}
204160814Ssimon#endif
205160814Ssimon
206160814Ssimon/* Product of two polynomials a, b each with degree < 2 * BN_BITS2 - 1,
207160814Ssimon * result is a polynomial r with degree < 4 * BN_BITS2 - 1
208160814Ssimon * The caller MUST ensure that the variables have the right amount
209160814Ssimon * of space allocated.
210160814Ssimon */
211160814Ssimonstatic void bn_GF2m_mul_2x2(BN_ULONG *r, const BN_ULONG a1, const BN_ULONG a0, const BN_ULONG b1, const BN_ULONG b0)
212160814Ssimon	{
213160814Ssimon	BN_ULONG m1, m0;
214160814Ssimon	/* r[3] = h1, r[2] = h0; r[1] = l1; r[0] = l0 */
215160814Ssimon	bn_GF2m_mul_1x1(r+3, r+2, a1, b1);
216160814Ssimon	bn_GF2m_mul_1x1(r+1, r, a0, b0);
217160814Ssimon	bn_GF2m_mul_1x1(&m1, &m0, a0 ^ a1, b0 ^ b1);
218160814Ssimon	/* Correction on m1 ^= l1 ^ h1; m0 ^= l0 ^ h0; */
219160814Ssimon	r[2] ^= m1 ^ r[1] ^ r[3];  /* h0 ^= m1 ^ l1 ^ h1; */
220160814Ssimon	r[1] = r[3] ^ r[2] ^ r[0] ^ m1 ^ m0;  /* l1 ^= l0 ^ h0 ^ m0; */
221160814Ssimon	}
222238405Sjkim#else
223238405Sjkimvoid bn_GF2m_mul_2x2(BN_ULONG *r, BN_ULONG a1, BN_ULONG a0, BN_ULONG b1, BN_ULONG b0);
224238405Sjkim#endif
225160814Ssimon
226160814Ssimon/* Add polynomials a and b and store result in r; r could be a or b, a and b
227160814Ssimon * could be equal; r is the bitwise XOR of a and b.
228160814Ssimon */
229160814Ssimonint	BN_GF2m_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
230160814Ssimon	{
231160814Ssimon	int i;
232160814Ssimon	const BIGNUM *at, *bt;
233160814Ssimon
234160814Ssimon	bn_check_top(a);
235160814Ssimon	bn_check_top(b);
236160814Ssimon
237160814Ssimon	if (a->top < b->top) { at = b; bt = a; }
238160814Ssimon	else { at = a; bt = b; }
239160814Ssimon
240205128Ssimon	if(bn_wexpand(r, at->top) == NULL)
241205128Ssimon		return 0;
242160814Ssimon
243160814Ssimon	for (i = 0; i < bt->top; i++)
244160814Ssimon		{
245160814Ssimon		r->d[i] = at->d[i] ^ bt->d[i];
246160814Ssimon		}
247160814Ssimon	for (; i < at->top; i++)
248160814Ssimon		{
249160814Ssimon		r->d[i] = at->d[i];
250160814Ssimon		}
251160814Ssimon
252160814Ssimon	r->top = at->top;
253160814Ssimon	bn_correct_top(r);
254160814Ssimon
255160814Ssimon	return 1;
256160814Ssimon	}
257160814Ssimon
258160814Ssimon
259160814Ssimon/* Some functions allow for representation of the irreducible polynomials
260160814Ssimon * as an int[], say p.  The irreducible f(t) is then of the form:
261160814Ssimon *     t^p[0] + t^p[1] + ... + t^p[k]
262160814Ssimon * where m = p[0] > p[1] > ... > p[k] = 0.
263160814Ssimon */
264160814Ssimon
265160814Ssimon
266160814Ssimon/* Performs modular reduction of a and store result in r.  r could be a. */
267238405Sjkimint BN_GF2m_mod_arr(BIGNUM *r, const BIGNUM *a, const int p[])
268160814Ssimon	{
269160814Ssimon	int j, k;
270160814Ssimon	int n, dN, d0, d1;
271160814Ssimon	BN_ULONG zz, *z;
272160814Ssimon
273160814Ssimon	bn_check_top(a);
274160814Ssimon
275160814Ssimon	if (!p[0])
276160814Ssimon		{
277160814Ssimon		/* reduction mod 1 => return 0 */
278160814Ssimon		BN_zero(r);
279160814Ssimon		return 1;
280160814Ssimon		}
281160814Ssimon
282160814Ssimon	/* Since the algorithm does reduction in the r value, if a != r, copy
283160814Ssimon	 * the contents of a into r so we can do reduction in r.
284160814Ssimon	 */
285160814Ssimon	if (a != r)
286160814Ssimon		{
287160814Ssimon		if (!bn_wexpand(r, a->top)) return 0;
288160814Ssimon		for (j = 0; j < a->top; j++)
289160814Ssimon			{
290160814Ssimon			r->d[j] = a->d[j];
291160814Ssimon			}
292160814Ssimon		r->top = a->top;
293160814Ssimon		}
294160814Ssimon	z = r->d;
295160814Ssimon
296160814Ssimon	/* start reduction */
297160814Ssimon	dN = p[0] / BN_BITS2;
298160814Ssimon	for (j = r->top - 1; j > dN;)
299160814Ssimon		{
300160814Ssimon		zz = z[j];
301160814Ssimon		if (z[j] == 0) { j--; continue; }
302160814Ssimon		z[j] = 0;
303160814Ssimon
304160814Ssimon		for (k = 1; p[k] != 0; k++)
305160814Ssimon			{
306160814Ssimon			/* reducing component t^p[k] */
307160814Ssimon			n = p[0] - p[k];
308160814Ssimon			d0 = n % BN_BITS2;  d1 = BN_BITS2 - d0;
309160814Ssimon			n /= BN_BITS2;
310160814Ssimon			z[j-n] ^= (zz>>d0);
311160814Ssimon			if (d0) z[j-n-1] ^= (zz<<d1);
312160814Ssimon			}
313160814Ssimon
314160814Ssimon		/* reducing component t^0 */
315160814Ssimon		n = dN;
316160814Ssimon		d0 = p[0] % BN_BITS2;
317160814Ssimon		d1 = BN_BITS2 - d0;
318160814Ssimon		z[j-n] ^= (zz >> d0);
319160814Ssimon		if (d0) z[j-n-1] ^= (zz << d1);
320160814Ssimon		}
321160814Ssimon
322160814Ssimon	/* final round of reduction */
323160814Ssimon	while (j == dN)
324160814Ssimon		{
325160814Ssimon
326160814Ssimon		d0 = p[0] % BN_BITS2;
327160814Ssimon		zz = z[dN] >> d0;
328160814Ssimon		if (zz == 0) break;
329160814Ssimon		d1 = BN_BITS2 - d0;
330160814Ssimon
331194206Ssimon		/* clear up the top d1 bits */
332194206Ssimon		if (d0)
333194206Ssimon			z[dN] = (z[dN] << d1) >> d1;
334194206Ssimon		else
335194206Ssimon			z[dN] = 0;
336160814Ssimon		z[0] ^= zz; /* reduction t^0 component */
337160814Ssimon
338160814Ssimon		for (k = 1; p[k] != 0; k++)
339160814Ssimon			{
340160814Ssimon			BN_ULONG tmp_ulong;
341160814Ssimon
342160814Ssimon			/* reducing component t^p[k]*/
343160814Ssimon			n = p[k] / BN_BITS2;
344160814Ssimon			d0 = p[k] % BN_BITS2;
345160814Ssimon			d1 = BN_BITS2 - d0;
346160814Ssimon			z[n] ^= (zz << d0);
347160814Ssimon			tmp_ulong = zz >> d1;
348160814Ssimon                        if (d0 && tmp_ulong)
349160814Ssimon                                z[n+1] ^= tmp_ulong;
350160814Ssimon			}
351160814Ssimon
352160814Ssimon
353160814Ssimon		}
354160814Ssimon
355160814Ssimon	bn_correct_top(r);
356160814Ssimon	return 1;
357160814Ssimon	}
358160814Ssimon
359160814Ssimon/* Performs modular reduction of a by p and store result in r.  r could be a.
360160814Ssimon *
361160814Ssimon * This function calls down to the BN_GF2m_mod_arr implementation; this wrapper
362160814Ssimon * function is only provided for convenience; for best performance, use the
363160814Ssimon * BN_GF2m_mod_arr function.
364160814Ssimon */
365160814Ssimonint	BN_GF2m_mod(BIGNUM *r, const BIGNUM *a, const BIGNUM *p)
366160814Ssimon	{
367160814Ssimon	int ret = 0;
368238405Sjkim	int arr[6];
369160814Ssimon	bn_check_top(a);
370160814Ssimon	bn_check_top(p);
371238405Sjkim	ret = BN_GF2m_poly2arr(p, arr, sizeof(arr)/sizeof(arr[0]));
372238405Sjkim	if (!ret || ret > (int)(sizeof(arr)/sizeof(arr[0])))
373160814Ssimon		{
374160814Ssimon		BNerr(BN_F_BN_GF2M_MOD,BN_R_INVALID_LENGTH);
375238405Sjkim		return 0;
376160814Ssimon		}
377160814Ssimon	ret = BN_GF2m_mod_arr(r, a, arr);
378160814Ssimon	bn_check_top(r);
379160814Ssimon	return ret;
380160814Ssimon	}
381160814Ssimon
382160814Ssimon
383160814Ssimon/* Compute the product of two polynomials a and b, reduce modulo p, and store
384160814Ssimon * the result in r.  r could be a or b; a could be b.
385160814Ssimon */
386238405Sjkimint	BN_GF2m_mod_mul_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const int p[], BN_CTX *ctx)
387160814Ssimon	{
388160814Ssimon	int zlen, i, j, k, ret = 0;
389160814Ssimon	BIGNUM *s;
390160814Ssimon	BN_ULONG x1, x0, y1, y0, zz[4];
391160814Ssimon
392160814Ssimon	bn_check_top(a);
393160814Ssimon	bn_check_top(b);
394160814Ssimon
395160814Ssimon	if (a == b)
396160814Ssimon		{
397160814Ssimon		return BN_GF2m_mod_sqr_arr(r, a, p, ctx);
398160814Ssimon		}
399160814Ssimon
400160814Ssimon	BN_CTX_start(ctx);
401160814Ssimon	if ((s = BN_CTX_get(ctx)) == NULL) goto err;
402160814Ssimon
403160814Ssimon	zlen = a->top + b->top + 4;
404160814Ssimon	if (!bn_wexpand(s, zlen)) goto err;
405160814Ssimon	s->top = zlen;
406160814Ssimon
407160814Ssimon	for (i = 0; i < zlen; i++) s->d[i] = 0;
408160814Ssimon
409160814Ssimon	for (j = 0; j < b->top; j += 2)
410160814Ssimon		{
411160814Ssimon		y0 = b->d[j];
412160814Ssimon		y1 = ((j+1) == b->top) ? 0 : b->d[j+1];
413160814Ssimon		for (i = 0; i < a->top; i += 2)
414160814Ssimon			{
415160814Ssimon			x0 = a->d[i];
416160814Ssimon			x1 = ((i+1) == a->top) ? 0 : a->d[i+1];
417160814Ssimon			bn_GF2m_mul_2x2(zz, x1, x0, y1, y0);
418160814Ssimon			for (k = 0; k < 4; k++) s->d[i+j+k] ^= zz[k];
419160814Ssimon			}
420160814Ssimon		}
421160814Ssimon
422160814Ssimon	bn_correct_top(s);
423160814Ssimon	if (BN_GF2m_mod_arr(r, s, p))
424160814Ssimon		ret = 1;
425160814Ssimon	bn_check_top(r);
426160814Ssimon
427160814Ssimonerr:
428160814Ssimon	BN_CTX_end(ctx);
429160814Ssimon	return ret;
430160814Ssimon	}
431160814Ssimon
432160814Ssimon/* Compute the product of two polynomials a and b, reduce modulo p, and store
433160814Ssimon * the result in r.  r could be a or b; a could equal b.
434160814Ssimon *
435160814Ssimon * This function calls down to the BN_GF2m_mod_mul_arr implementation; this wrapper
436160814Ssimon * function is only provided for convenience; for best performance, use the
437160814Ssimon * BN_GF2m_mod_mul_arr function.
438160814Ssimon */
439160814Ssimonint	BN_GF2m_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *p, BN_CTX *ctx)
440160814Ssimon	{
441160814Ssimon	int ret = 0;
442238405Sjkim	const int max = BN_num_bits(p) + 1;
443238405Sjkim	int *arr=NULL;
444160814Ssimon	bn_check_top(a);
445160814Ssimon	bn_check_top(b);
446160814Ssimon	bn_check_top(p);
447238405Sjkim	if ((arr = (int *)OPENSSL_malloc(sizeof(int) * max)) == NULL) goto err;
448160814Ssimon	ret = BN_GF2m_poly2arr(p, arr, max);
449160814Ssimon	if (!ret || ret > max)
450160814Ssimon		{
451160814Ssimon		BNerr(BN_F_BN_GF2M_MOD_MUL,BN_R_INVALID_LENGTH);
452160814Ssimon		goto err;
453160814Ssimon		}
454160814Ssimon	ret = BN_GF2m_mod_mul_arr(r, a, b, arr, ctx);
455160814Ssimon	bn_check_top(r);
456160814Ssimonerr:
457160814Ssimon	if (arr) OPENSSL_free(arr);
458160814Ssimon	return ret;
459160814Ssimon	}
460160814Ssimon
461160814Ssimon
462160814Ssimon/* Square a, reduce the result mod p, and store it in a.  r could be a. */
463238405Sjkimint	BN_GF2m_mod_sqr_arr(BIGNUM *r, const BIGNUM *a, const int p[], BN_CTX *ctx)
464160814Ssimon	{
465160814Ssimon	int i, ret = 0;
466160814Ssimon	BIGNUM *s;
467160814Ssimon
468160814Ssimon	bn_check_top(a);
469160814Ssimon	BN_CTX_start(ctx);
470160814Ssimon	if ((s = BN_CTX_get(ctx)) == NULL) return 0;
471160814Ssimon	if (!bn_wexpand(s, 2 * a->top)) goto err;
472160814Ssimon
473160814Ssimon	for (i = a->top - 1; i >= 0; i--)
474160814Ssimon		{
475160814Ssimon		s->d[2*i+1] = SQR1(a->d[i]);
476160814Ssimon		s->d[2*i  ] = SQR0(a->d[i]);
477160814Ssimon		}
478160814Ssimon
479160814Ssimon	s->top = 2 * a->top;
480160814Ssimon	bn_correct_top(s);
481160814Ssimon	if (!BN_GF2m_mod_arr(r, s, p)) goto err;
482160814Ssimon	bn_check_top(r);
483160814Ssimon	ret = 1;
484160814Ssimonerr:
485160814Ssimon	BN_CTX_end(ctx);
486160814Ssimon	return ret;
487160814Ssimon	}
488160814Ssimon
489160814Ssimon/* Square a, reduce the result mod p, and store it in a.  r could be a.
490160814Ssimon *
491160814Ssimon * This function calls down to the BN_GF2m_mod_sqr_arr implementation; this wrapper
492160814Ssimon * function is only provided for convenience; for best performance, use the
493160814Ssimon * BN_GF2m_mod_sqr_arr function.
494160814Ssimon */
495160814Ssimonint	BN_GF2m_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx)
496160814Ssimon	{
497160814Ssimon	int ret = 0;
498238405Sjkim	const int max = BN_num_bits(p) + 1;
499238405Sjkim	int *arr=NULL;
500160814Ssimon
501160814Ssimon	bn_check_top(a);
502160814Ssimon	bn_check_top(p);
503238405Sjkim	if ((arr = (int *)OPENSSL_malloc(sizeof(int) * max)) == NULL) goto err;
504160814Ssimon	ret = BN_GF2m_poly2arr(p, arr, max);
505160814Ssimon	if (!ret || ret > max)
506160814Ssimon		{
507160814Ssimon		BNerr(BN_F_BN_GF2M_MOD_SQR,BN_R_INVALID_LENGTH);
508160814Ssimon		goto err;
509160814Ssimon		}
510160814Ssimon	ret = BN_GF2m_mod_sqr_arr(r, a, arr, ctx);
511160814Ssimon	bn_check_top(r);
512160814Ssimonerr:
513160814Ssimon	if (arr) OPENSSL_free(arr);
514160814Ssimon	return ret;
515160814Ssimon	}
516160814Ssimon
517160814Ssimon
518160814Ssimon/* Invert a, reduce modulo p, and store the result in r. r could be a.
519160814Ssimon * Uses Modified Almost Inverse Algorithm (Algorithm 10) from
520160814Ssimon *     Hankerson, D., Hernandez, J.L., and Menezes, A.  "Software Implementation
521160814Ssimon *     of Elliptic Curve Cryptography Over Binary Fields".
522160814Ssimon */
523160814Ssimonint BN_GF2m_mod_inv(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx)
524160814Ssimon	{
525238405Sjkim	BIGNUM *b, *c = NULL, *u = NULL, *v = NULL, *tmp;
526160814Ssimon	int ret = 0;
527160814Ssimon
528160814Ssimon	bn_check_top(a);
529160814Ssimon	bn_check_top(p);
530160814Ssimon
531160814Ssimon	BN_CTX_start(ctx);
532160814Ssimon
533238405Sjkim	if ((b = BN_CTX_get(ctx))==NULL) goto err;
534238405Sjkim	if ((c = BN_CTX_get(ctx))==NULL) goto err;
535238405Sjkim	if ((u = BN_CTX_get(ctx))==NULL) goto err;
536238405Sjkim	if ((v = BN_CTX_get(ctx))==NULL) goto err;
537160814Ssimon
538160814Ssimon	if (!BN_GF2m_mod(u, a, p)) goto err;
539238405Sjkim	if (BN_is_zero(u)) goto err;
540238405Sjkim
541160814Ssimon	if (!BN_copy(v, p)) goto err;
542238405Sjkim#if 0
543238405Sjkim	if (!BN_one(b)) goto err;
544160814Ssimon
545160814Ssimon	while (1)
546160814Ssimon		{
547160814Ssimon		while (!BN_is_odd(u))
548160814Ssimon			{
549237657Sjkim			if (BN_is_zero(u)) goto err;
550160814Ssimon			if (!BN_rshift1(u, u)) goto err;
551160814Ssimon			if (BN_is_odd(b))
552160814Ssimon				{
553160814Ssimon				if (!BN_GF2m_add(b, b, p)) goto err;
554160814Ssimon				}
555160814Ssimon			if (!BN_rshift1(b, b)) goto err;
556160814Ssimon			}
557160814Ssimon
558160814Ssimon		if (BN_abs_is_word(u, 1)) break;
559160814Ssimon
560160814Ssimon		if (BN_num_bits(u) < BN_num_bits(v))
561160814Ssimon			{
562160814Ssimon			tmp = u; u = v; v = tmp;
563160814Ssimon			tmp = b; b = c; c = tmp;
564160814Ssimon			}
565160814Ssimon
566160814Ssimon		if (!BN_GF2m_add(u, u, v)) goto err;
567160814Ssimon		if (!BN_GF2m_add(b, b, c)) goto err;
568160814Ssimon		}
569238405Sjkim#else
570238405Sjkim	{
571238405Sjkim	int i,	ubits = BN_num_bits(u),
572238405Sjkim		vbits = BN_num_bits(v),	/* v is copy of p */
573238405Sjkim		top = p->top;
574238405Sjkim	BN_ULONG *udp,*bdp,*vdp,*cdp;
575160814Ssimon
576238405Sjkim	bn_wexpand(u,top);	udp = u->d;
577238405Sjkim				for (i=u->top;i<top;i++) udp[i] = 0;
578238405Sjkim				u->top = top;
579238405Sjkim	bn_wexpand(b,top);	bdp = b->d;
580238405Sjkim				bdp[0] = 1;
581238405Sjkim				for (i=1;i<top;i++) bdp[i] = 0;
582238405Sjkim				b->top = top;
583238405Sjkim	bn_wexpand(c,top);	cdp = c->d;
584238405Sjkim				for (i=0;i<top;i++) cdp[i] = 0;
585238405Sjkim				c->top = top;
586238405Sjkim	vdp = v->d;	/* It pays off to "cache" *->d pointers, because
587238405Sjkim			 * it allows optimizer to be more aggressive.
588238405Sjkim			 * But we don't have to "cache" p->d, because *p
589238405Sjkim			 * is declared 'const'... */
590238405Sjkim	while (1)
591238405Sjkim		{
592238405Sjkim		while (ubits && !(udp[0]&1))
593238405Sjkim			{
594238405Sjkim			BN_ULONG u0,u1,b0,b1,mask;
595160814Ssimon
596238405Sjkim			u0   = udp[0];
597238405Sjkim			b0   = bdp[0];
598238405Sjkim			mask = (BN_ULONG)0-(b0&1);
599238405Sjkim			b0  ^= p->d[0]&mask;
600238405Sjkim			for (i=0;i<top-1;i++)
601238405Sjkim				{
602238405Sjkim				u1 = udp[i+1];
603238405Sjkim				udp[i] = ((u0>>1)|(u1<<(BN_BITS2-1)))&BN_MASK2;
604238405Sjkim				u0 = u1;
605238405Sjkim				b1 = bdp[i+1]^(p->d[i+1]&mask);
606238405Sjkim				bdp[i] = ((b0>>1)|(b1<<(BN_BITS2-1)))&BN_MASK2;
607238405Sjkim				b0 = b1;
608238405Sjkim				}
609238405Sjkim			udp[i] = u0>>1;
610238405Sjkim			bdp[i] = b0>>1;
611238405Sjkim			ubits--;
612238405Sjkim			}
613238405Sjkim
614238405Sjkim		if (ubits<=BN_BITS2 && udp[0]==1) break;
615238405Sjkim
616238405Sjkim		if (ubits<vbits)
617238405Sjkim			{
618238405Sjkim			i = ubits; ubits = vbits; vbits = i;
619238405Sjkim			tmp = u; u = v; v = tmp;
620238405Sjkim			tmp = b; b = c; c = tmp;
621238405Sjkim			udp = vdp; vdp = v->d;
622238405Sjkim			bdp = cdp; cdp = c->d;
623238405Sjkim			}
624238405Sjkim		for(i=0;i<top;i++)
625238405Sjkim			{
626238405Sjkim			udp[i] ^= vdp[i];
627238405Sjkim			bdp[i] ^= cdp[i];
628238405Sjkim			}
629238405Sjkim		if (ubits==vbits)
630238405Sjkim			{
631238405Sjkim			BN_ULONG ul;
632238405Sjkim			int utop = (ubits-1)/BN_BITS2;
633238405Sjkim
634238405Sjkim			while ((ul=udp[utop])==0 && utop) utop--;
635238405Sjkim			ubits = utop*BN_BITS2 + BN_num_bits_word(ul);
636238405Sjkim			}
637238405Sjkim		}
638238405Sjkim	bn_correct_top(b);
639238405Sjkim	}
640238405Sjkim#endif
641238405Sjkim
642160814Ssimon	if (!BN_copy(r, b)) goto err;
643160814Ssimon	bn_check_top(r);
644160814Ssimon	ret = 1;
645160814Ssimon
646160814Ssimonerr:
647238405Sjkim#ifdef BN_DEBUG /* BN_CTX_end would complain about the expanded form */
648238405Sjkim        bn_correct_top(c);
649238405Sjkim        bn_correct_top(u);
650238405Sjkim        bn_correct_top(v);
651238405Sjkim#endif
652160814Ssimon  	BN_CTX_end(ctx);
653160814Ssimon	return ret;
654160814Ssimon	}
655160814Ssimon
656160814Ssimon/* Invert xx, reduce modulo p, and store the result in r. r could be xx.
657160814Ssimon *
658160814Ssimon * This function calls down to the BN_GF2m_mod_inv implementation; this wrapper
659160814Ssimon * function is only provided for convenience; for best performance, use the
660160814Ssimon * BN_GF2m_mod_inv function.
661160814Ssimon */
662238405Sjkimint BN_GF2m_mod_inv_arr(BIGNUM *r, const BIGNUM *xx, const int p[], BN_CTX *ctx)
663160814Ssimon	{
664160814Ssimon	BIGNUM *field;
665160814Ssimon	int ret = 0;
666160814Ssimon
667160814Ssimon	bn_check_top(xx);
668160814Ssimon	BN_CTX_start(ctx);
669160814Ssimon	if ((field = BN_CTX_get(ctx)) == NULL) goto err;
670160814Ssimon	if (!BN_GF2m_arr2poly(p, field)) goto err;
671160814Ssimon
672160814Ssimon	ret = BN_GF2m_mod_inv(r, xx, field, ctx);
673160814Ssimon	bn_check_top(r);
674160814Ssimon
675160814Ssimonerr:
676160814Ssimon	BN_CTX_end(ctx);
677160814Ssimon	return ret;
678160814Ssimon	}
679160814Ssimon
680160814Ssimon
681160814Ssimon#ifndef OPENSSL_SUN_GF2M_DIV
682160814Ssimon/* Divide y by x, reduce modulo p, and store the result in r. r could be x
683160814Ssimon * or y, x could equal y.
684160814Ssimon */
685160814Ssimonint BN_GF2m_mod_div(BIGNUM *r, const BIGNUM *y, const BIGNUM *x, const BIGNUM *p, BN_CTX *ctx)
686160814Ssimon	{
687160814Ssimon	BIGNUM *xinv = NULL;
688160814Ssimon	int ret = 0;
689160814Ssimon
690160814Ssimon	bn_check_top(y);
691160814Ssimon	bn_check_top(x);
692160814Ssimon	bn_check_top(p);
693160814Ssimon
694160814Ssimon	BN_CTX_start(ctx);
695160814Ssimon	xinv = BN_CTX_get(ctx);
696160814Ssimon	if (xinv == NULL) goto err;
697160814Ssimon
698160814Ssimon	if (!BN_GF2m_mod_inv(xinv, x, p, ctx)) goto err;
699160814Ssimon	if (!BN_GF2m_mod_mul(r, y, xinv, p, ctx)) goto err;
700160814Ssimon	bn_check_top(r);
701160814Ssimon	ret = 1;
702160814Ssimon
703160814Ssimonerr:
704160814Ssimon	BN_CTX_end(ctx);
705160814Ssimon	return ret;
706160814Ssimon	}
707160814Ssimon#else
708160814Ssimon/* Divide y by x, reduce modulo p, and store the result in r. r could be x
709160814Ssimon * or y, x could equal y.
710160814Ssimon * Uses algorithm Modular_Division_GF(2^m) from
711160814Ssimon *     Chang-Shantz, S.  "From Euclid's GCD to Montgomery Multiplication to
712160814Ssimon *     the Great Divide".
713160814Ssimon */
714160814Ssimonint BN_GF2m_mod_div(BIGNUM *r, const BIGNUM *y, const BIGNUM *x, const BIGNUM *p, BN_CTX *ctx)
715160814Ssimon	{
716160814Ssimon	BIGNUM *a, *b, *u, *v;
717160814Ssimon	int ret = 0;
718160814Ssimon
719160814Ssimon	bn_check_top(y);
720160814Ssimon	bn_check_top(x);
721160814Ssimon	bn_check_top(p);
722160814Ssimon
723160814Ssimon	BN_CTX_start(ctx);
724160814Ssimon
725160814Ssimon	a = BN_CTX_get(ctx);
726160814Ssimon	b = BN_CTX_get(ctx);
727160814Ssimon	u = BN_CTX_get(ctx);
728160814Ssimon	v = BN_CTX_get(ctx);
729160814Ssimon	if (v == NULL) goto err;
730160814Ssimon
731160814Ssimon	/* reduce x and y mod p */
732160814Ssimon	if (!BN_GF2m_mod(u, y, p)) goto err;
733160814Ssimon	if (!BN_GF2m_mod(a, x, p)) goto err;
734160814Ssimon	if (!BN_copy(b, p)) goto err;
735160814Ssimon
736160814Ssimon	while (!BN_is_odd(a))
737160814Ssimon		{
738160814Ssimon		if (!BN_rshift1(a, a)) goto err;
739160814Ssimon		if (BN_is_odd(u)) if (!BN_GF2m_add(u, u, p)) goto err;
740160814Ssimon		if (!BN_rshift1(u, u)) goto err;
741160814Ssimon		}
742160814Ssimon
743160814Ssimon	do
744160814Ssimon		{
745160814Ssimon		if (BN_GF2m_cmp(b, a) > 0)
746160814Ssimon			{
747160814Ssimon			if (!BN_GF2m_add(b, b, a)) goto err;
748160814Ssimon			if (!BN_GF2m_add(v, v, u)) goto err;
749160814Ssimon			do
750160814Ssimon				{
751160814Ssimon				if (!BN_rshift1(b, b)) goto err;
752160814Ssimon				if (BN_is_odd(v)) if (!BN_GF2m_add(v, v, p)) goto err;
753160814Ssimon				if (!BN_rshift1(v, v)) goto err;
754160814Ssimon				} while (!BN_is_odd(b));
755160814Ssimon			}
756160814Ssimon		else if (BN_abs_is_word(a, 1))
757160814Ssimon			break;
758160814Ssimon		else
759160814Ssimon			{
760160814Ssimon			if (!BN_GF2m_add(a, a, b)) goto err;
761160814Ssimon			if (!BN_GF2m_add(u, u, v)) goto err;
762160814Ssimon			do
763160814Ssimon				{
764160814Ssimon				if (!BN_rshift1(a, a)) goto err;
765160814Ssimon				if (BN_is_odd(u)) if (!BN_GF2m_add(u, u, p)) goto err;
766160814Ssimon				if (!BN_rshift1(u, u)) goto err;
767160814Ssimon				} while (!BN_is_odd(a));
768160814Ssimon			}
769160814Ssimon		} while (1);
770160814Ssimon
771160814Ssimon	if (!BN_copy(r, u)) goto err;
772160814Ssimon	bn_check_top(r);
773160814Ssimon	ret = 1;
774160814Ssimon
775160814Ssimonerr:
776160814Ssimon  	BN_CTX_end(ctx);
777160814Ssimon	return ret;
778160814Ssimon	}
779160814Ssimon#endif
780160814Ssimon
781160814Ssimon/* Divide yy by xx, reduce modulo p, and store the result in r. r could be xx
782160814Ssimon * or yy, xx could equal yy.
783160814Ssimon *
784160814Ssimon * This function calls down to the BN_GF2m_mod_div implementation; this wrapper
785160814Ssimon * function is only provided for convenience; for best performance, use the
786160814Ssimon * BN_GF2m_mod_div function.
787160814Ssimon */
788238405Sjkimint BN_GF2m_mod_div_arr(BIGNUM *r, const BIGNUM *yy, const BIGNUM *xx, const int p[], BN_CTX *ctx)
789160814Ssimon	{
790160814Ssimon	BIGNUM *field;
791160814Ssimon	int ret = 0;
792160814Ssimon
793160814Ssimon	bn_check_top(yy);
794160814Ssimon	bn_check_top(xx);
795160814Ssimon
796160814Ssimon	BN_CTX_start(ctx);
797160814Ssimon	if ((field = BN_CTX_get(ctx)) == NULL) goto err;
798160814Ssimon	if (!BN_GF2m_arr2poly(p, field)) goto err;
799160814Ssimon
800160814Ssimon	ret = BN_GF2m_mod_div(r, yy, xx, field, ctx);
801160814Ssimon	bn_check_top(r);
802160814Ssimon
803160814Ssimonerr:
804160814Ssimon	BN_CTX_end(ctx);
805160814Ssimon	return ret;
806160814Ssimon	}
807160814Ssimon
808160814Ssimon
809160814Ssimon/* Compute the bth power of a, reduce modulo p, and store
810160814Ssimon * the result in r.  r could be a.
811160814Ssimon * Uses simple square-and-multiply algorithm A.5.1 from IEEE P1363.
812160814Ssimon */
813238405Sjkimint	BN_GF2m_mod_exp_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const int p[], BN_CTX *ctx)
814160814Ssimon	{
815160814Ssimon	int ret = 0, i, n;
816160814Ssimon	BIGNUM *u;
817160814Ssimon
818160814Ssimon	bn_check_top(a);
819160814Ssimon	bn_check_top(b);
820160814Ssimon
821160814Ssimon	if (BN_is_zero(b))
822160814Ssimon		return(BN_one(r));
823160814Ssimon
824160814Ssimon	if (BN_abs_is_word(b, 1))
825160814Ssimon		return (BN_copy(r, a) != NULL);
826160814Ssimon
827160814Ssimon	BN_CTX_start(ctx);
828160814Ssimon	if ((u = BN_CTX_get(ctx)) == NULL) goto err;
829160814Ssimon
830160814Ssimon	if (!BN_GF2m_mod_arr(u, a, p)) goto err;
831160814Ssimon
832160814Ssimon	n = BN_num_bits(b) - 1;
833160814Ssimon	for (i = n - 1; i >= 0; i--)
834160814Ssimon		{
835160814Ssimon		if (!BN_GF2m_mod_sqr_arr(u, u, p, ctx)) goto err;
836160814Ssimon		if (BN_is_bit_set(b, i))
837160814Ssimon			{
838160814Ssimon			if (!BN_GF2m_mod_mul_arr(u, u, a, p, ctx)) goto err;
839160814Ssimon			}
840160814Ssimon		}
841160814Ssimon	if (!BN_copy(r, u)) goto err;
842160814Ssimon	bn_check_top(r);
843160814Ssimon	ret = 1;
844160814Ssimonerr:
845160814Ssimon	BN_CTX_end(ctx);
846160814Ssimon	return ret;
847160814Ssimon	}
848160814Ssimon
849160814Ssimon/* Compute the bth power of a, reduce modulo p, and store
850160814Ssimon * the result in r.  r could be a.
851160814Ssimon *
852160814Ssimon * This function calls down to the BN_GF2m_mod_exp_arr implementation; this wrapper
853160814Ssimon * function is only provided for convenience; for best performance, use the
854160814Ssimon * BN_GF2m_mod_exp_arr function.
855160814Ssimon */
856160814Ssimonint BN_GF2m_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *p, BN_CTX *ctx)
857160814Ssimon	{
858160814Ssimon	int ret = 0;
859238405Sjkim	const int max = BN_num_bits(p) + 1;
860238405Sjkim	int *arr=NULL;
861160814Ssimon	bn_check_top(a);
862160814Ssimon	bn_check_top(b);
863160814Ssimon	bn_check_top(p);
864238405Sjkim	if ((arr = (int *)OPENSSL_malloc(sizeof(int) * max)) == NULL) goto err;
865160814Ssimon	ret = BN_GF2m_poly2arr(p, arr, max);
866160814Ssimon	if (!ret || ret > max)
867160814Ssimon		{
868160814Ssimon		BNerr(BN_F_BN_GF2M_MOD_EXP,BN_R_INVALID_LENGTH);
869160814Ssimon		goto err;
870160814Ssimon		}
871160814Ssimon	ret = BN_GF2m_mod_exp_arr(r, a, b, arr, ctx);
872160814Ssimon	bn_check_top(r);
873160814Ssimonerr:
874160814Ssimon	if (arr) OPENSSL_free(arr);
875160814Ssimon	return ret;
876160814Ssimon	}
877160814Ssimon
878160814Ssimon/* Compute the square root of a, reduce modulo p, and store
879160814Ssimon * the result in r.  r could be a.
880160814Ssimon * Uses exponentiation as in algorithm A.4.1 from IEEE P1363.
881160814Ssimon */
882238405Sjkimint	BN_GF2m_mod_sqrt_arr(BIGNUM *r, const BIGNUM *a, const int p[], BN_CTX *ctx)
883160814Ssimon	{
884160814Ssimon	int ret = 0;
885160814Ssimon	BIGNUM *u;
886160814Ssimon
887160814Ssimon	bn_check_top(a);
888160814Ssimon
889160814Ssimon	if (!p[0])
890160814Ssimon		{
891160814Ssimon		/* reduction mod 1 => return 0 */
892160814Ssimon		BN_zero(r);
893160814Ssimon		return 1;
894160814Ssimon		}
895160814Ssimon
896160814Ssimon	BN_CTX_start(ctx);
897160814Ssimon	if ((u = BN_CTX_get(ctx)) == NULL) goto err;
898160814Ssimon
899160814Ssimon	if (!BN_set_bit(u, p[0] - 1)) goto err;
900160814Ssimon	ret = BN_GF2m_mod_exp_arr(r, a, u, p, ctx);
901160814Ssimon	bn_check_top(r);
902160814Ssimon
903160814Ssimonerr:
904160814Ssimon	BN_CTX_end(ctx);
905160814Ssimon	return ret;
906160814Ssimon	}
907160814Ssimon
908160814Ssimon/* Compute the square root of a, reduce modulo p, and store
909160814Ssimon * the result in r.  r could be a.
910160814Ssimon *
911160814Ssimon * This function calls down to the BN_GF2m_mod_sqrt_arr implementation; this wrapper
912160814Ssimon * function is only provided for convenience; for best performance, use the
913160814Ssimon * BN_GF2m_mod_sqrt_arr function.
914160814Ssimon */
915160814Ssimonint BN_GF2m_mod_sqrt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx)
916160814Ssimon	{
917160814Ssimon	int ret = 0;
918238405Sjkim	const int max = BN_num_bits(p) + 1;
919238405Sjkim	int *arr=NULL;
920160814Ssimon	bn_check_top(a);
921160814Ssimon	bn_check_top(p);
922238405Sjkim	if ((arr = (int *)OPENSSL_malloc(sizeof(int) * max)) == NULL) goto err;
923160814Ssimon	ret = BN_GF2m_poly2arr(p, arr, max);
924160814Ssimon	if (!ret || ret > max)
925160814Ssimon		{
926160814Ssimon		BNerr(BN_F_BN_GF2M_MOD_SQRT,BN_R_INVALID_LENGTH);
927160814Ssimon		goto err;
928160814Ssimon		}
929160814Ssimon	ret = BN_GF2m_mod_sqrt_arr(r, a, arr, ctx);
930160814Ssimon	bn_check_top(r);
931160814Ssimonerr:
932160814Ssimon	if (arr) OPENSSL_free(arr);
933160814Ssimon	return ret;
934160814Ssimon	}
935160814Ssimon
936160814Ssimon/* Find r such that r^2 + r = a mod p.  r could be a. If no r exists returns 0.
937160814Ssimon * Uses algorithms A.4.7 and A.4.6 from IEEE P1363.
938160814Ssimon */
939238405Sjkimint BN_GF2m_mod_solve_quad_arr(BIGNUM *r, const BIGNUM *a_, const int p[], BN_CTX *ctx)
940160814Ssimon	{
941238405Sjkim	int ret = 0, count = 0, j;
942160814Ssimon	BIGNUM *a, *z, *rho, *w, *w2, *tmp;
943160814Ssimon
944160814Ssimon	bn_check_top(a_);
945160814Ssimon
946160814Ssimon	if (!p[0])
947160814Ssimon		{
948160814Ssimon		/* reduction mod 1 => return 0 */
949160814Ssimon		BN_zero(r);
950160814Ssimon		return 1;
951160814Ssimon		}
952160814Ssimon
953160814Ssimon	BN_CTX_start(ctx);
954160814Ssimon	a = BN_CTX_get(ctx);
955160814Ssimon	z = BN_CTX_get(ctx);
956160814Ssimon	w = BN_CTX_get(ctx);
957160814Ssimon	if (w == NULL) goto err;
958160814Ssimon
959160814Ssimon	if (!BN_GF2m_mod_arr(a, a_, p)) goto err;
960160814Ssimon
961160814Ssimon	if (BN_is_zero(a))
962160814Ssimon		{
963160814Ssimon		BN_zero(r);
964160814Ssimon		ret = 1;
965160814Ssimon		goto err;
966160814Ssimon		}
967160814Ssimon
968160814Ssimon	if (p[0] & 0x1) /* m is odd */
969160814Ssimon		{
970160814Ssimon		/* compute half-trace of a */
971160814Ssimon		if (!BN_copy(z, a)) goto err;
972160814Ssimon		for (j = 1; j <= (p[0] - 1) / 2; j++)
973160814Ssimon			{
974160814Ssimon			if (!BN_GF2m_mod_sqr_arr(z, z, p, ctx)) goto err;
975160814Ssimon			if (!BN_GF2m_mod_sqr_arr(z, z, p, ctx)) goto err;
976160814Ssimon			if (!BN_GF2m_add(z, z, a)) goto err;
977160814Ssimon			}
978160814Ssimon
979160814Ssimon		}
980160814Ssimon	else /* m is even */
981160814Ssimon		{
982160814Ssimon		rho = BN_CTX_get(ctx);
983160814Ssimon		w2 = BN_CTX_get(ctx);
984160814Ssimon		tmp = BN_CTX_get(ctx);
985160814Ssimon		if (tmp == NULL) goto err;
986160814Ssimon		do
987160814Ssimon			{
988160814Ssimon			if (!BN_rand(rho, p[0], 0, 0)) goto err;
989160814Ssimon			if (!BN_GF2m_mod_arr(rho, rho, p)) goto err;
990160814Ssimon			BN_zero(z);
991160814Ssimon			if (!BN_copy(w, rho)) goto err;
992160814Ssimon			for (j = 1; j <= p[0] - 1; j++)
993160814Ssimon				{
994160814Ssimon				if (!BN_GF2m_mod_sqr_arr(z, z, p, ctx)) goto err;
995160814Ssimon				if (!BN_GF2m_mod_sqr_arr(w2, w, p, ctx)) goto err;
996160814Ssimon				if (!BN_GF2m_mod_mul_arr(tmp, w2, a, p, ctx)) goto err;
997160814Ssimon				if (!BN_GF2m_add(z, z, tmp)) goto err;
998160814Ssimon				if (!BN_GF2m_add(w, w2, rho)) goto err;
999160814Ssimon				}
1000160814Ssimon			count++;
1001160814Ssimon			} while (BN_is_zero(w) && (count < MAX_ITERATIONS));
1002160814Ssimon		if (BN_is_zero(w))
1003160814Ssimon			{
1004160814Ssimon			BNerr(BN_F_BN_GF2M_MOD_SOLVE_QUAD_ARR,BN_R_TOO_MANY_ITERATIONS);
1005160814Ssimon			goto err;
1006160814Ssimon			}
1007160814Ssimon		}
1008160814Ssimon
1009160814Ssimon	if (!BN_GF2m_mod_sqr_arr(w, z, p, ctx)) goto err;
1010160814Ssimon	if (!BN_GF2m_add(w, z, w)) goto err;
1011160814Ssimon	if (BN_GF2m_cmp(w, a))
1012160814Ssimon		{
1013160814Ssimon		BNerr(BN_F_BN_GF2M_MOD_SOLVE_QUAD_ARR, BN_R_NO_SOLUTION);
1014160814Ssimon		goto err;
1015160814Ssimon		}
1016160814Ssimon
1017160814Ssimon	if (!BN_copy(r, z)) goto err;
1018160814Ssimon	bn_check_top(r);
1019160814Ssimon
1020160814Ssimon	ret = 1;
1021160814Ssimon
1022160814Ssimonerr:
1023160814Ssimon	BN_CTX_end(ctx);
1024160814Ssimon	return ret;
1025160814Ssimon	}
1026160814Ssimon
1027160814Ssimon/* Find r such that r^2 + r = a mod p.  r could be a. If no r exists returns 0.
1028160814Ssimon *
1029160814Ssimon * This function calls down to the BN_GF2m_mod_solve_quad_arr implementation; this wrapper
1030160814Ssimon * function is only provided for convenience; for best performance, use the
1031160814Ssimon * BN_GF2m_mod_solve_quad_arr function.
1032160814Ssimon */
1033160814Ssimonint BN_GF2m_mod_solve_quad(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx)
1034160814Ssimon	{
1035160814Ssimon	int ret = 0;
1036238405Sjkim	const int max = BN_num_bits(p) + 1;
1037238405Sjkim	int *arr=NULL;
1038160814Ssimon	bn_check_top(a);
1039160814Ssimon	bn_check_top(p);
1040238405Sjkim	if ((arr = (int *)OPENSSL_malloc(sizeof(int) *
1041160814Ssimon						max)) == NULL) goto err;
1042160814Ssimon	ret = BN_GF2m_poly2arr(p, arr, max);
1043160814Ssimon	if (!ret || ret > max)
1044160814Ssimon		{
1045160814Ssimon		BNerr(BN_F_BN_GF2M_MOD_SOLVE_QUAD,BN_R_INVALID_LENGTH);
1046160814Ssimon		goto err;
1047160814Ssimon		}
1048160814Ssimon	ret = BN_GF2m_mod_solve_quad_arr(r, a, arr, ctx);
1049160814Ssimon	bn_check_top(r);
1050160814Ssimonerr:
1051160814Ssimon	if (arr) OPENSSL_free(arr);
1052160814Ssimon	return ret;
1053160814Ssimon	}
1054160814Ssimon
1055160814Ssimon/* Convert the bit-string representation of a polynomial
1056238405Sjkim * ( \sum_{i=0}^n a_i * x^i) into an array of integers corresponding
1057238405Sjkim * to the bits with non-zero coefficient.  Array is terminated with -1.
1058160814Ssimon * Up to max elements of the array will be filled.  Return value is total
1059238405Sjkim * number of array elements that would be filled if array was large enough.
1060160814Ssimon */
1061238405Sjkimint BN_GF2m_poly2arr(const BIGNUM *a, int p[], int max)
1062160814Ssimon	{
1063160814Ssimon	int i, j, k = 0;
1064160814Ssimon	BN_ULONG mask;
1065160814Ssimon
1066238405Sjkim	if (BN_is_zero(a))
1067160814Ssimon		return 0;
1068160814Ssimon
1069160814Ssimon	for (i = a->top - 1; i >= 0; i--)
1070160814Ssimon		{
1071160814Ssimon		if (!a->d[i])
1072160814Ssimon			/* skip word if a->d[i] == 0 */
1073160814Ssimon			continue;
1074160814Ssimon		mask = BN_TBIT;
1075160814Ssimon		for (j = BN_BITS2 - 1; j >= 0; j--)
1076160814Ssimon			{
1077160814Ssimon			if (a->d[i] & mask)
1078160814Ssimon				{
1079160814Ssimon				if (k < max) p[k] = BN_BITS2 * i + j;
1080160814Ssimon				k++;
1081160814Ssimon				}
1082160814Ssimon			mask >>= 1;
1083160814Ssimon			}
1084160814Ssimon		}
1085160814Ssimon
1086238405Sjkim	if (k < max) {
1087238405Sjkim		p[k] = -1;
1088238405Sjkim		k++;
1089238405Sjkim	}
1090238405Sjkim
1091160814Ssimon	return k;
1092160814Ssimon	}
1093160814Ssimon
1094160814Ssimon/* Convert the coefficient array representation of a polynomial to a
1095238405Sjkim * bit-string.  The array must be terminated by -1.
1096160814Ssimon */
1097238405Sjkimint BN_GF2m_arr2poly(const int p[], BIGNUM *a)
1098160814Ssimon	{
1099160814Ssimon	int i;
1100160814Ssimon
1101160814Ssimon	bn_check_top(a);
1102160814Ssimon	BN_zero(a);
1103238405Sjkim	for (i = 0; p[i] != -1; i++)
1104160814Ssimon		{
1105160814Ssimon		if (BN_set_bit(a, p[i]) == 0)
1106160814Ssimon			return 0;
1107160814Ssimon		}
1108160814Ssimon	bn_check_top(a);
1109160814Ssimon
1110160814Ssimon	return 1;
1111160814Ssimon	}
1112160814Ssimon
1113238405Sjkim#endif
1114