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.
8296341Sdelphij *
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).
15296341Sdelphij *
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.
22296341Sdelphij *
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 :-).
37296341Sdelphij * 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)"
40296341Sdelphij *
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.
52296341Sdelphij *
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 */
64296341Sdelphij/*
65296341Sdelphij * I've just gone over this and it is now %20 faster on x86 - eay - 27 Jun 96
66296341Sdelphij */
67109998Smarkmint BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
68296341Sdelphij{
69296341Sdelphij    int max, al;
70296341Sdelphij    int ret = 0;
71296341Sdelphij    BIGNUM *tmp, *rr;
7255714Skris
7355714Skris#ifdef BN_COUNT
74296341Sdelphij    fprintf(stderr, "BN_sqr %d * %d\n", a->top, a->top);
7555714Skris#endif
76296341Sdelphij    bn_check_top(a);
7755714Skris
78296341Sdelphij    al = a->top;
79296341Sdelphij    if (al <= 0) {
80296341Sdelphij        r->top = 0;
81296341Sdelphij        r->neg = 0;
82296341Sdelphij        return 1;
83296341Sdelphij    }
8455714Skris
85296341Sdelphij    BN_CTX_start(ctx);
86296341Sdelphij    rr = (a != r) ? r : BN_CTX_get(ctx);
87296341Sdelphij    tmp = BN_CTX_get(ctx);
88296341Sdelphij    if (!rr || !tmp)
89296341Sdelphij        goto err;
9059191Skris
91296341Sdelphij    max = 2 * al;               /* Non-zero (from above) */
92296341Sdelphij    if (bn_wexpand(rr, max) == NULL)
93296341Sdelphij        goto err;
9455714Skris
95296341Sdelphij    if (al == 4) {
9655714Skris#ifndef BN_SQR_COMBA
97296341Sdelphij        BN_ULONG t[8];
98296341Sdelphij        bn_sqr_normal(rr->d, a->d, 4, t);
9955714Skris#else
100296341Sdelphij        bn_sqr_comba4(rr->d, a->d);
10155714Skris#endif
102296341Sdelphij    } else if (al == 8) {
10355714Skris#ifndef BN_SQR_COMBA
104296341Sdelphij        BN_ULONG t[16];
105296341Sdelphij        bn_sqr_normal(rr->d, a->d, 8, t);
10655714Skris#else
107296341Sdelphij        bn_sqr_comba8(rr->d, a->d);
10855714Skris#endif
109296341Sdelphij    } else {
11055714Skris#if defined(BN_RECURSION)
111296341Sdelphij        if (al < BN_SQR_RECURSIVE_SIZE_NORMAL) {
112296341Sdelphij            BN_ULONG t[BN_SQR_RECURSIVE_SIZE_NORMAL * 2];
113296341Sdelphij            bn_sqr_normal(rr->d, a->d, al, t);
114296341Sdelphij        } else {
115296341Sdelphij            int j, k;
11655714Skris
117296341Sdelphij            j = BN_num_bits_word((BN_ULONG)al);
118296341Sdelphij            j = 1 << (j - 1);
119296341Sdelphij            k = j + j;
120296341Sdelphij            if (al == j) {
121296341Sdelphij                if (bn_wexpand(tmp, k * 2) == NULL)
122296341Sdelphij                    goto err;
123296341Sdelphij                bn_sqr_recursive(rr->d, a->d, al, tmp->d);
124296341Sdelphij            } else {
125296341Sdelphij                if (bn_wexpand(tmp, max) == NULL)
126296341Sdelphij                    goto err;
127296341Sdelphij                bn_sqr_normal(rr->d, a->d, al, tmp->d);
128296341Sdelphij            }
129296341Sdelphij        }
13055714Skris#else
131296341Sdelphij        if (bn_wexpand(tmp, max) == NULL)
132296341Sdelphij            goto err;
133296341Sdelphij        bn_sqr_normal(rr->d, a->d, al, tmp->d);
13455714Skris#endif
135296341Sdelphij    }
13655714Skris
137296341Sdelphij    rr->neg = 0;
138296341Sdelphij    /*
139296341Sdelphij     * If the most-significant half of the top word of 'a' is zero, then the
140296341Sdelphij     * square of 'a' will max-1 words.
141296341Sdelphij     */
142296341Sdelphij    if (a->d[al - 1] == (a->d[al - 1] & BN_MASK2l))
143296341Sdelphij        rr->top = max - 1;
144296341Sdelphij    else
145296341Sdelphij        rr->top = max;
146296341Sdelphij    if (rr != r)
147296341Sdelphij        BN_copy(r, rr);
148296341Sdelphij    ret = 1;
14959191Skris err:
150296341Sdelphij    bn_check_top(rr);
151296341Sdelphij    bn_check_top(tmp);
152296341Sdelphij    BN_CTX_end(ctx);
153296341Sdelphij    return (ret);
154296341Sdelphij}
15555714Skris
15655714Skris/* tmp must have 2*n words */
157109998Smarkmvoid bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, int n, BN_ULONG *tmp)
158296341Sdelphij{
159296341Sdelphij    int i, j, max;
160296341Sdelphij    const BN_ULONG *ap;
161296341Sdelphij    BN_ULONG *rp;
16255714Skris
163296341Sdelphij    max = n * 2;
164296341Sdelphij    ap = a;
165296341Sdelphij    rp = r;
166296341Sdelphij    rp[0] = rp[max - 1] = 0;
167296341Sdelphij    rp++;
168296341Sdelphij    j = n;
16955714Skris
170296341Sdelphij    if (--j > 0) {
171296341Sdelphij        ap++;
172296341Sdelphij        rp[j] = bn_mul_words(rp, ap, j, ap[-1]);
173296341Sdelphij        rp += 2;
174296341Sdelphij    }
17555714Skris
176296341Sdelphij    for (i = n - 2; i > 0; i--) {
177296341Sdelphij        j--;
178296341Sdelphij        ap++;
179296341Sdelphij        rp[j] = bn_mul_add_words(rp, ap, j, ap[-1]);
180296341Sdelphij        rp += 2;
181296341Sdelphij    }
18255714Skris
183296341Sdelphij    bn_add_words(r, r, r, max);
18455714Skris
185296341Sdelphij    /* There will not be a carry */
18655714Skris
187296341Sdelphij    bn_sqr_words(tmp, a, n);
18855714Skris
189296341Sdelphij    bn_add_words(r, r, tmp, max);
190296341Sdelphij}
19155714Skris
19255714Skris#ifdef BN_RECURSION
193296341Sdelphij/*-
194296341Sdelphij * 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)
205296341Sdelphij{
206296341Sdelphij    int n = n2 / 2;
207296341Sdelphij    int zero, c1;
208296341Sdelphij    BN_ULONG ln, lo, *p;
20955714Skris
210296341Sdelphij# ifdef BN_COUNT
211296341Sdelphij    fprintf(stderr, " bn_sqr_recursive %d * %d\n", n2, n2);
212296341Sdelphij# endif
213296341Sdelphij    if (n2 == 4) {
214296341Sdelphij# ifndef BN_SQR_COMBA
215296341Sdelphij        bn_sqr_normal(r, a, 4, t);
216296341Sdelphij# else
217296341Sdelphij        bn_sqr_comba4(r, a);
218296341Sdelphij# endif
219296341Sdelphij        return;
220296341Sdelphij    } else if (n2 == 8) {
221296341Sdelphij# ifndef BN_SQR_COMBA
222296341Sdelphij        bn_sqr_normal(r, a, 8, t);
223296341Sdelphij# else
224296341Sdelphij        bn_sqr_comba8(r, a);
225296341Sdelphij# endif
226296341Sdelphij        return;
227296341Sdelphij    }
228296341Sdelphij    if (n2 < BN_SQR_RECURSIVE_SIZE_NORMAL) {
229296341Sdelphij        bn_sqr_normal(r, a, n2, t);
230296341Sdelphij        return;
231296341Sdelphij    }
232296341Sdelphij    /* r=(a[0]-a[1])*(a[1]-a[0]) */
233296341Sdelphij    c1 = bn_cmp_words(a, &(a[n]), n);
234296341Sdelphij    zero = 0;
235296341Sdelphij    if (c1 > 0)
236296341Sdelphij        bn_sub_words(t, a, &(a[n]), n);
237296341Sdelphij    else if (c1 < 0)
238296341Sdelphij        bn_sub_words(t, &(a[n]), a, n);
239296341Sdelphij    else
240296341Sdelphij        zero = 1;
24155714Skris
242296341Sdelphij    /* The result will always be negative unless it is zero */
243296341Sdelphij    p = &(t[n2 * 2]);
24455714Skris
245296341Sdelphij    if (!zero)
246296341Sdelphij        bn_sqr_recursive(&(t[n2]), t, n, p);
247296341Sdelphij    else
248296341Sdelphij        memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG));
249296341Sdelphij    bn_sqr_recursive(r, a, n, p);
250296341Sdelphij    bn_sqr_recursive(&(r[n2]), &(a[n]), n, p);
25155714Skris
252296341Sdelphij    /*-
253296341Sdelphij     * t[32] holds (a[0]-a[1])*(a[1]-a[0]), it is negative or zero
254296341Sdelphij     * r[10] holds (a[0]*b[0])
255296341Sdelphij     * r[32] holds (b[1]*b[1])
256296341Sdelphij     */
25755714Skris
258296341Sdelphij    c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
25955714Skris
260296341Sdelphij    /* t[32] is negative */
261296341Sdelphij    c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
26255714Skris
263296341Sdelphij    /*-
264296341Sdelphij     * t[32] holds (a[0]-a[1])*(a[1]-a[0])+(a[0]*a[0])+(a[1]*a[1])
265296341Sdelphij     * r[10] holds (a[0]*a[0])
266296341Sdelphij     * r[32] holds (a[1]*a[1])
267296341Sdelphij     * c1 holds the carry bits
268296341Sdelphij     */
269296341Sdelphij    c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
270296341Sdelphij    if (c1) {
271296341Sdelphij        p = &(r[n + n2]);
272296341Sdelphij        lo = *p;
273296341Sdelphij        ln = (lo + c1) & BN_MASK2;
274296341Sdelphij        *p = ln;
27555714Skris
276296341Sdelphij        /*
277296341Sdelphij         * The overflow will stop before we over write words we should not
278296341Sdelphij         * overwrite
279296341Sdelphij         */
280296341Sdelphij        if (ln < (BN_ULONG)c1) {
281296341Sdelphij            do {
282296341Sdelphij                p++;
283296341Sdelphij                lo = *p;
284296341Sdelphij                ln = (lo + 1) & BN_MASK2;
285296341Sdelphij                *p = ln;
286296341Sdelphij            } while (ln == 0);
287296341Sdelphij        }
288296341Sdelphij    }
289296341Sdelphij}
29055714Skris#endif
291