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.
8280297Sjkim *
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).
15280297Sjkim *
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.
22280297Sjkim *
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 :-).
37280297Sjkim * 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)"
40280297Sjkim *
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.
52280297Sjkim *
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 */
64280297Sjkim/*
65280297Sjkim * I've just gone over this and it is now %20 faster on x86 - eay - 27 Jun 96
66280297Sjkim */
67109998Smarkmint BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
68280297Sjkim{
69340704Sjkim    int ret = bn_sqr_fixed_top(r, a, ctx);
70340704Sjkim
71340704Sjkim    bn_correct_top(r);
72340704Sjkim    bn_check_top(r);
73340704Sjkim
74340704Sjkim    return ret;
75340704Sjkim}
76340704Sjkim
77340704Sjkimint bn_sqr_fixed_top(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
78340704Sjkim{
79280297Sjkim    int max, al;
80280297Sjkim    int ret = 0;
81280297Sjkim    BIGNUM *tmp, *rr;
8255714Skris
8355714Skris#ifdef BN_COUNT
84280297Sjkim    fprintf(stderr, "BN_sqr %d * %d\n", a->top, a->top);
8555714Skris#endif
86280297Sjkim    bn_check_top(a);
8755714Skris
88280297Sjkim    al = a->top;
89280297Sjkim    if (al <= 0) {
90280297Sjkim        r->top = 0;
91280297Sjkim        r->neg = 0;
92280297Sjkim        return 1;
93280297Sjkim    }
9455714Skris
95280297Sjkim    BN_CTX_start(ctx);
96280297Sjkim    rr = (a != r) ? r : BN_CTX_get(ctx);
97280297Sjkim    tmp = BN_CTX_get(ctx);
98280297Sjkim    if (!rr || !tmp)
99280297Sjkim        goto err;
10059191Skris
101280297Sjkim    max = 2 * al;               /* Non-zero (from above) */
102280297Sjkim    if (bn_wexpand(rr, max) == NULL)
103280297Sjkim        goto err;
10455714Skris
105280297Sjkim    if (al == 4) {
10655714Skris#ifndef BN_SQR_COMBA
107280297Sjkim        BN_ULONG t[8];
108280297Sjkim        bn_sqr_normal(rr->d, a->d, 4, t);
10955714Skris#else
110280297Sjkim        bn_sqr_comba4(rr->d, a->d);
11155714Skris#endif
112280297Sjkim    } else if (al == 8) {
11355714Skris#ifndef BN_SQR_COMBA
114280297Sjkim        BN_ULONG t[16];
115280297Sjkim        bn_sqr_normal(rr->d, a->d, 8, t);
11655714Skris#else
117280297Sjkim        bn_sqr_comba8(rr->d, a->d);
11855714Skris#endif
119280297Sjkim    } else {
12055714Skris#if defined(BN_RECURSION)
121280297Sjkim        if (al < BN_SQR_RECURSIVE_SIZE_NORMAL) {
122280297Sjkim            BN_ULONG t[BN_SQR_RECURSIVE_SIZE_NORMAL * 2];
123280297Sjkim            bn_sqr_normal(rr->d, a->d, al, t);
124280297Sjkim        } else {
125280297Sjkim            int j, k;
12655714Skris
127280297Sjkim            j = BN_num_bits_word((BN_ULONG)al);
128280297Sjkim            j = 1 << (j - 1);
129280297Sjkim            k = j + j;
130280297Sjkim            if (al == j) {
131280297Sjkim                if (bn_wexpand(tmp, k * 2) == NULL)
132280297Sjkim                    goto err;
133280297Sjkim                bn_sqr_recursive(rr->d, a->d, al, tmp->d);
134280297Sjkim            } else {
135280297Sjkim                if (bn_wexpand(tmp, max) == NULL)
136280297Sjkim                    goto err;
137280297Sjkim                bn_sqr_normal(rr->d, a->d, al, tmp->d);
138280297Sjkim            }
139280297Sjkim        }
14055714Skris#else
141280297Sjkim        if (bn_wexpand(tmp, max) == NULL)
142280297Sjkim            goto err;
143280297Sjkim        bn_sqr_normal(rr->d, a->d, al, tmp->d);
14455714Skris#endif
145280297Sjkim    }
14655714Skris
147280297Sjkim    rr->neg = 0;
148337982Sjkim    rr->top = max;
149340704Sjkim    rr->flags |= BN_FLG_FIXED_TOP;
150312826Sjkim    if (r != rr && BN_copy(r, rr) == NULL)
151312826Sjkim        goto err;
152312826Sjkim
153280297Sjkim    ret = 1;
15459191Skris err:
155280297Sjkim    bn_check_top(rr);
156280297Sjkim    bn_check_top(tmp);
157280297Sjkim    BN_CTX_end(ctx);
158280297Sjkim    return (ret);
159280297Sjkim}
16055714Skris
16155714Skris/* tmp must have 2*n words */
162109998Smarkmvoid bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, int n, BN_ULONG *tmp)
163280297Sjkim{
164280297Sjkim    int i, j, max;
165280297Sjkim    const BN_ULONG *ap;
166280297Sjkim    BN_ULONG *rp;
16755714Skris
168280297Sjkim    max = n * 2;
169280297Sjkim    ap = a;
170280297Sjkim    rp = r;
171280297Sjkim    rp[0] = rp[max - 1] = 0;
172280297Sjkim    rp++;
173280297Sjkim    j = n;
17455714Skris
175280297Sjkim    if (--j > 0) {
176280297Sjkim        ap++;
177280297Sjkim        rp[j] = bn_mul_words(rp, ap, j, ap[-1]);
178280297Sjkim        rp += 2;
179280297Sjkim    }
18055714Skris
181280297Sjkim    for (i = n - 2; i > 0; i--) {
182280297Sjkim        j--;
183280297Sjkim        ap++;
184280297Sjkim        rp[j] = bn_mul_add_words(rp, ap, j, ap[-1]);
185280297Sjkim        rp += 2;
186280297Sjkim    }
18755714Skris
188280297Sjkim    bn_add_words(r, r, r, max);
18955714Skris
190280297Sjkim    /* There will not be a carry */
19155714Skris
192280297Sjkim    bn_sqr_words(tmp, a, n);
19355714Skris
194280297Sjkim    bn_add_words(r, r, tmp, max);
195280297Sjkim}
19655714Skris
19755714Skris#ifdef BN_RECURSION
198280297Sjkim/*-
199280297Sjkim * r is 2*n words in size,
20068651Skris * a and b are both n words in size.    (There's not actually a 'b' here ...)
20155714Skris * n must be a power of 2.
20255714Skris * We multiply and return the result.
20355714Skris * t must be 2*n words in size
20459191Skris * We calculate
20555714Skris * a[0]*b[0]
20655714Skris * a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0])
20755714Skris * a[1]*b[1]
20855714Skris */
209109998Smarkmvoid bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t)
210280297Sjkim{
211280297Sjkim    int n = n2 / 2;
212280297Sjkim    int zero, c1;
213280297Sjkim    BN_ULONG ln, lo, *p;
21455714Skris
215280297Sjkim# ifdef BN_COUNT
216280297Sjkim    fprintf(stderr, " bn_sqr_recursive %d * %d\n", n2, n2);
217280297Sjkim# endif
218280297Sjkim    if (n2 == 4) {
219280297Sjkim# ifndef BN_SQR_COMBA
220280297Sjkim        bn_sqr_normal(r, a, 4, t);
221280297Sjkim# else
222280297Sjkim        bn_sqr_comba4(r, a);
223280297Sjkim# endif
224280297Sjkim        return;
225280297Sjkim    } else if (n2 == 8) {
226280297Sjkim# ifndef BN_SQR_COMBA
227280297Sjkim        bn_sqr_normal(r, a, 8, t);
228280297Sjkim# else
229280297Sjkim        bn_sqr_comba8(r, a);
230280297Sjkim# endif
231280297Sjkim        return;
232280297Sjkim    }
233280297Sjkim    if (n2 < BN_SQR_RECURSIVE_SIZE_NORMAL) {
234280297Sjkim        bn_sqr_normal(r, a, n2, t);
235280297Sjkim        return;
236280297Sjkim    }
237280297Sjkim    /* r=(a[0]-a[1])*(a[1]-a[0]) */
238280297Sjkim    c1 = bn_cmp_words(a, &(a[n]), n);
239280297Sjkim    zero = 0;
240280297Sjkim    if (c1 > 0)
241280297Sjkim        bn_sub_words(t, a, &(a[n]), n);
242280297Sjkim    else if (c1 < 0)
243280297Sjkim        bn_sub_words(t, &(a[n]), a, n);
244280297Sjkim    else
245280297Sjkim        zero = 1;
24655714Skris
247280297Sjkim    /* The result will always be negative unless it is zero */
248280297Sjkim    p = &(t[n2 * 2]);
24955714Skris
250280297Sjkim    if (!zero)
251280297Sjkim        bn_sqr_recursive(&(t[n2]), t, n, p);
252280297Sjkim    else
253280297Sjkim        memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG));
254280297Sjkim    bn_sqr_recursive(r, a, n, p);
255280297Sjkim    bn_sqr_recursive(&(r[n2]), &(a[n]), n, p);
25655714Skris
257280297Sjkim    /*-
258280297Sjkim     * t[32] holds (a[0]-a[1])*(a[1]-a[0]), it is negative or zero
259280297Sjkim     * r[10] holds (a[0]*b[0])
260280297Sjkim     * r[32] holds (b[1]*b[1])
261280297Sjkim     */
26255714Skris
263280297Sjkim    c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
26455714Skris
265280297Sjkim    /* t[32] is negative */
266280297Sjkim    c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
26755714Skris
268280297Sjkim    /*-
269280297Sjkim     * t[32] holds (a[0]-a[1])*(a[1]-a[0])+(a[0]*a[0])+(a[1]*a[1])
270280297Sjkim     * r[10] holds (a[0]*a[0])
271280297Sjkim     * r[32] holds (a[1]*a[1])
272280297Sjkim     * c1 holds the carry bits
273280297Sjkim     */
274280297Sjkim    c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
275280297Sjkim    if (c1) {
276280297Sjkim        p = &(r[n + n2]);
277280297Sjkim        lo = *p;
278280297Sjkim        ln = (lo + c1) & BN_MASK2;
279280297Sjkim        *p = ln;
28055714Skris
281280297Sjkim        /*
282280297Sjkim         * The overflow will stop before we over write words we should not
283280297Sjkim         * overwrite
284280297Sjkim         */
285280297Sjkim        if (ln < (BN_ULONG)c1) {
286280297Sjkim            do {
287280297Sjkim                p++;
288280297Sjkim                lo = *p;
289280297Sjkim                ln = (lo + 1) & BN_MASK2;
290280297Sjkim                *p = ln;
291280297Sjkim            } while (ln == 0);
292280297Sjkim        }
293280297Sjkim    }
294280297Sjkim}
29555714Skris#endif
296