155714Skris/* crypto/bn/bn_sqr.c */
255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
355714Skris * All rights reserved.
455714Skris *
555714Skris * This package is an SSL implementation written
655714Skris * by Eric Young (eay@cryptsoft.com).
755714Skris * The implementation was written so as to conform with Netscapes SSL.
8280304Sjkim *
955714Skris * This library is free for commercial and non-commercial use as long as
1055714Skris * the following conditions are aheared to.  The following conditions
1155714Skris * apply to all code found in this distribution, be it the RC4, RSA,
1255714Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1355714Skris * included with this distribution is covered by the same copyright terms
1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15280304Sjkim *
1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1755714Skris * the code are not to be removed.
1855714Skris * If this package is used in a product, Eric Young should be given attribution
1955714Skris * as the author of the parts of the library used.
2055714Skris * This can be in the form of a textual message at program startup or
2155714Skris * in documentation (online or textual) provided with the package.
22280304Sjkim *
2355714Skris * Redistribution and use in source and binary forms, with or without
2455714Skris * modification, are permitted provided that the following conditions
2555714Skris * are met:
2655714Skris * 1. Redistributions of source code must retain the copyright
2755714Skris *    notice, this list of conditions and the following disclaimer.
2855714Skris * 2. Redistributions in binary form must reproduce the above copyright
2955714Skris *    notice, this list of conditions and the following disclaimer in the
3055714Skris *    documentation and/or other materials provided with the distribution.
3155714Skris * 3. All advertising materials mentioning features or use of this software
3255714Skris *    must display the following acknowledgement:
3355714Skris *    "This product includes cryptographic software written by
3455714Skris *     Eric Young (eay@cryptsoft.com)"
3555714Skris *    The word 'cryptographic' can be left out if the rouines from the library
3655714Skris *    being used are not cryptographic related :-).
37280304Sjkim * 4. If you include any Windows specific code (or a derivative thereof) from
3855714Skris *    the apps directory (application code) you must include an acknowledgement:
3955714Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40280304Sjkim *
4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5155714Skris * SUCH DAMAGE.
52280304Sjkim *
5355714Skris * The licence and distribution terms for any publically available version or
5455714Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5555714Skris * copied and put under another distribution licence
5655714Skris * [including the GNU Public Licence.]
5755714Skris */
5855714Skris
5955714Skris#include <stdio.h>
6055714Skris#include "cryptlib.h"
6155714Skris#include "bn_lcl.h"
6255714Skris
6355714Skris/* r must not be a */
64280304Sjkim/*
65280304Sjkim * I've just gone over this and it is now %20 faster on x86 - eay - 27 Jun 96
66280304Sjkim */
67109998Smarkmint BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
68280304Sjkim{
69280304Sjkim    int max, al;
70280304Sjkim    int ret = 0;
71280304Sjkim    BIGNUM *tmp, *rr;
7255714Skris
7355714Skris#ifdef BN_COUNT
74280304Sjkim    fprintf(stderr, "BN_sqr %d * %d\n", a->top, a->top);
7555714Skris#endif
76280304Sjkim    bn_check_top(a);
7755714Skris
78280304Sjkim    al = a->top;
79280304Sjkim    if (al <= 0) {
80280304Sjkim        r->top = 0;
81280304Sjkim        r->neg = 0;
82280304Sjkim        return 1;
83280304Sjkim    }
8455714Skris
85280304Sjkim    BN_CTX_start(ctx);
86280304Sjkim    rr = (a != r) ? r : BN_CTX_get(ctx);
87280304Sjkim    tmp = BN_CTX_get(ctx);
88280304Sjkim    if (!rr || !tmp)
89280304Sjkim        goto err;
9059191Skris
91280304Sjkim    max = 2 * al;               /* Non-zero (from above) */
92280304Sjkim    if (bn_wexpand(rr, max) == NULL)
93280304Sjkim        goto err;
9455714Skris
95280304Sjkim    if (al == 4) {
9655714Skris#ifndef BN_SQR_COMBA
97280304Sjkim        BN_ULONG t[8];
98280304Sjkim        bn_sqr_normal(rr->d, a->d, 4, t);
9955714Skris#else
100280304Sjkim        bn_sqr_comba4(rr->d, a->d);
10155714Skris#endif
102280304Sjkim    } else if (al == 8) {
10355714Skris#ifndef BN_SQR_COMBA
104280304Sjkim        BN_ULONG t[16];
105280304Sjkim        bn_sqr_normal(rr->d, a->d, 8, t);
10655714Skris#else
107280304Sjkim        bn_sqr_comba8(rr->d, a->d);
10855714Skris#endif
109280304Sjkim    } else {
11055714Skris#if defined(BN_RECURSION)
111280304Sjkim        if (al < BN_SQR_RECURSIVE_SIZE_NORMAL) {
112280304Sjkim            BN_ULONG t[BN_SQR_RECURSIVE_SIZE_NORMAL * 2];
113280304Sjkim            bn_sqr_normal(rr->d, a->d, al, t);
114280304Sjkim        } else {
115280304Sjkim            int j, k;
11655714Skris
117280304Sjkim            j = BN_num_bits_word((BN_ULONG)al);
118280304Sjkim            j = 1 << (j - 1);
119280304Sjkim            k = j + j;
120280304Sjkim            if (al == j) {
121280304Sjkim                if (bn_wexpand(tmp, k * 2) == NULL)
122280304Sjkim                    goto err;
123280304Sjkim                bn_sqr_recursive(rr->d, a->d, al, tmp->d);
124280304Sjkim            } else {
125280304Sjkim                if (bn_wexpand(tmp, max) == NULL)
126280304Sjkim                    goto err;
127280304Sjkim                bn_sqr_normal(rr->d, a->d, al, tmp->d);
128280304Sjkim            }
129280304Sjkim        }
13055714Skris#else
131280304Sjkim        if (bn_wexpand(tmp, max) == NULL)
132280304Sjkim            goto err;
133280304Sjkim        bn_sqr_normal(rr->d, a->d, al, tmp->d);
13455714Skris#endif
135280304Sjkim    }
13655714Skris
137280304Sjkim    rr->neg = 0;
138280304Sjkim    /*
139280304Sjkim     * If the most-significant half of the top word of 'a' is zero, then the
140280304Sjkim     * square of 'a' will max-1 words.
141280304Sjkim     */
142280304Sjkim    if (a->d[al - 1] == (a->d[al - 1] & BN_MASK2l))
143280304Sjkim        rr->top = max - 1;
144280304Sjkim    else
145280304Sjkim        rr->top = max;
146280304Sjkim    if (rr != r)
147280304Sjkim        BN_copy(r, rr);
148280304Sjkim    ret = 1;
14959191Skris err:
150280304Sjkim    bn_check_top(rr);
151280304Sjkim    bn_check_top(tmp);
152280304Sjkim    BN_CTX_end(ctx);
153280304Sjkim    return (ret);
154280304Sjkim}
15555714Skris
15655714Skris/* tmp must have 2*n words */
157109998Smarkmvoid bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, int n, BN_ULONG *tmp)
158280304Sjkim{
159280304Sjkim    int i, j, max;
160280304Sjkim    const BN_ULONG *ap;
161280304Sjkim    BN_ULONG *rp;
16255714Skris
163280304Sjkim    max = n * 2;
164280304Sjkim    ap = a;
165280304Sjkim    rp = r;
166280304Sjkim    rp[0] = rp[max - 1] = 0;
167280304Sjkim    rp++;
168280304Sjkim    j = n;
16955714Skris
170280304Sjkim    if (--j > 0) {
171280304Sjkim        ap++;
172280304Sjkim        rp[j] = bn_mul_words(rp, ap, j, ap[-1]);
173280304Sjkim        rp += 2;
174280304Sjkim    }
17555714Skris
176280304Sjkim    for (i = n - 2; i > 0; i--) {
177280304Sjkim        j--;
178280304Sjkim        ap++;
179280304Sjkim        rp[j] = bn_mul_add_words(rp, ap, j, ap[-1]);
180280304Sjkim        rp += 2;
181280304Sjkim    }
18255714Skris
183280304Sjkim    bn_add_words(r, r, r, max);
18455714Skris
185280304Sjkim    /* There will not be a carry */
18655714Skris
187280304Sjkim    bn_sqr_words(tmp, a, n);
18855714Skris
189280304Sjkim    bn_add_words(r, r, tmp, max);
190280304Sjkim}
19155714Skris
19255714Skris#ifdef BN_RECURSION
193280304Sjkim/*-
194280304Sjkim * r is 2*n words in size,
19568651Skris * a and b are both n words in size.    (There's not actually a 'b' here ...)
19655714Skris * n must be a power of 2.
19755714Skris * We multiply and return the result.
19855714Skris * t must be 2*n words in size
19959191Skris * We calculate
20055714Skris * a[0]*b[0]
20155714Skris * a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0])
20255714Skris * a[1]*b[1]
20355714Skris */
204109998Smarkmvoid bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t)
205280304Sjkim{
206280304Sjkim    int n = n2 / 2;
207280304Sjkim    int zero, c1;
208280304Sjkim    BN_ULONG ln, lo, *p;
20955714Skris
210280304Sjkim# ifdef BN_COUNT
211280304Sjkim    fprintf(stderr, " bn_sqr_recursive %d * %d\n", n2, n2);
212280304Sjkim# endif
213280304Sjkim    if (n2 == 4) {
214280304Sjkim# ifndef BN_SQR_COMBA
215280304Sjkim        bn_sqr_normal(r, a, 4, t);
216280304Sjkim# else
217280304Sjkim        bn_sqr_comba4(r, a);
218280304Sjkim# endif
219280304Sjkim        return;
220280304Sjkim    } else if (n2 == 8) {
221280304Sjkim# ifndef BN_SQR_COMBA
222280304Sjkim        bn_sqr_normal(r, a, 8, t);
223280304Sjkim# else
224280304Sjkim        bn_sqr_comba8(r, a);
225280304Sjkim# endif
226280304Sjkim        return;
227280304Sjkim    }
228280304Sjkim    if (n2 < BN_SQR_RECURSIVE_SIZE_NORMAL) {
229280304Sjkim        bn_sqr_normal(r, a, n2, t);
230280304Sjkim        return;
231280304Sjkim    }
232280304Sjkim    /* r=(a[0]-a[1])*(a[1]-a[0]) */
233280304Sjkim    c1 = bn_cmp_words(a, &(a[n]), n);
234280304Sjkim    zero = 0;
235280304Sjkim    if (c1 > 0)
236280304Sjkim        bn_sub_words(t, a, &(a[n]), n);
237280304Sjkim    else if (c1 < 0)
238280304Sjkim        bn_sub_words(t, &(a[n]), a, n);
239280304Sjkim    else
240280304Sjkim        zero = 1;
24155714Skris
242280304Sjkim    /* The result will always be negative unless it is zero */
243280304Sjkim    p = &(t[n2 * 2]);
24455714Skris
245280304Sjkim    if (!zero)
246280304Sjkim        bn_sqr_recursive(&(t[n2]), t, n, p);
247280304Sjkim    else
248280304Sjkim        memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG));
249280304Sjkim    bn_sqr_recursive(r, a, n, p);
250280304Sjkim    bn_sqr_recursive(&(r[n2]), &(a[n]), n, p);
25155714Skris
252280304Sjkim    /*-
253280304Sjkim     * t[32] holds (a[0]-a[1])*(a[1]-a[0]), it is negative or zero
254280304Sjkim     * r[10] holds (a[0]*b[0])
255280304Sjkim     * r[32] holds (b[1]*b[1])
256280304Sjkim     */
25755714Skris
258280304Sjkim    c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
25955714Skris
260280304Sjkim    /* t[32] is negative */
261280304Sjkim    c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
26255714Skris
263280304Sjkim    /*-
264280304Sjkim     * t[32] holds (a[0]-a[1])*(a[1]-a[0])+(a[0]*a[0])+(a[1]*a[1])
265280304Sjkim     * r[10] holds (a[0]*a[0])
266280304Sjkim     * r[32] holds (a[1]*a[1])
267280304Sjkim     * c1 holds the carry bits
268280304Sjkim     */
269280304Sjkim    c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
270280304Sjkim    if (c1) {
271280304Sjkim        p = &(r[n + n2]);
272280304Sjkim        lo = *p;
273280304Sjkim        ln = (lo + c1) & BN_MASK2;
274280304Sjkim        *p = ln;
27555714Skris
276280304Sjkim        /*
277280304Sjkim         * The overflow will stop before we over write words we should not
278280304Sjkim         * overwrite
279280304Sjkim         */
280280304Sjkim        if (ln < (BN_ULONG)c1) {
281280304Sjkim            do {
282280304Sjkim                p++;
283280304Sjkim                lo = *p;
284280304Sjkim                ln = (lo + 1) & BN_MASK2;
285280304Sjkim                *p = ln;
286280304Sjkim            } while (ln == 0);
287280304Sjkim        }
288280304Sjkim    }
289280304Sjkim}
29055714Skris#endif
291