comparison bn_fast_s_mp_sqr.c @ 1:22d5cf7d4b1a libtommath

Renaming branch
author Matt Johnston <matt@ucc.asn.au>
date Mon, 31 May 2004 18:23:46 +0000
parents
children d29b64170cf0
comparison
equal deleted inserted replaced
-1:000000000000 1:22d5cf7d4b1a
1 /* LibTomMath, multiple-precision integer library -- Tom St Denis
2 *
3 * LibTomMath is a library that provides multiple-precision
4 * integer arithmetic as well as number theoretic functionality.
5 *
6 * The library was designed directly after the MPI library by
7 * Michael Fromberger but has been written from scratch with
8 * additional optimizations in place.
9 *
10 * The library is free for all purposes without any express
11 * guarantee it works.
12 *
13 * Tom St Denis, [email protected], http://math.libtomcrypt.org
14 */
15 #include <tommath.h>
16
17 /* fast squaring
18 *
19 * This is the comba method where the columns of the product
20 * are computed first then the carries are computed. This
21 * has the effect of making a very simple inner loop that
22 * is executed the most
23 *
24 * W2 represents the outer products and W the inner.
25 *
26 * A further optimizations is made because the inner
27 * products are of the form "A * B * 2". The *2 part does
28 * not need to be computed until the end which is good
29 * because 64-bit shifts are slow!
30 *
31 * Based on Algorithm 14.16 on pp.597 of HAC.
32 *
33 */
34 int fast_s_mp_sqr (mp_int * a, mp_int * b)
35 {
36 int olduse, newused, res, ix, pa;
37 mp_word W2[MP_WARRAY], W[MP_WARRAY];
38
39 /* calculate size of product and allocate as required */
40 pa = a->used;
41 newused = pa + pa + 1;
42 if (b->alloc < newused) {
43 if ((res = mp_grow (b, newused)) != MP_OKAY) {
44 return res;
45 }
46 }
47
48 /* zero temp buffer (columns)
49 * Note that there are two buffers. Since squaring requires
50 * a outer and inner product and the inner product requires
51 * computing a product and doubling it (a relatively expensive
52 * op to perform n**2 times if you don't have to) the inner and
53 * outer products are computed in different buffers. This way
54 * the inner product can be doubled using n doublings instead of
55 * n**2
56 */
57 memset (W, 0, newused * sizeof (mp_word));
58 memset (W2, 0, newused * sizeof (mp_word));
59
60 /* This computes the inner product. To simplify the inner N**2 loop
61 * the multiplication by two is done afterwards in the N loop.
62 */
63 for (ix = 0; ix < pa; ix++) {
64 /* compute the outer product
65 *
66 * Note that every outer product is computed
67 * for a particular column only once which means that
68 * there is no need todo a double precision addition
69 * into the W2[] array.
70 */
71 W2[ix + ix] = ((mp_word)a->dp[ix]) * ((mp_word)a->dp[ix]);
72
73 {
74 register mp_digit tmpx, *tmpy;
75 register mp_word *_W;
76 register int iy;
77
78 /* copy of left side */
79 tmpx = a->dp[ix];
80
81 /* alias for right side */
82 tmpy = a->dp + (ix + 1);
83
84 /* the column to store the result in */
85 _W = W + (ix + ix + 1);
86
87 /* inner products */
88 for (iy = ix + 1; iy < pa; iy++) {
89 *_W++ += ((mp_word)tmpx) * ((mp_word)*tmpy++);
90 }
91 }
92 }
93
94 /* setup dest */
95 olduse = b->used;
96 b->used = newused;
97
98 /* now compute digits
99 *
100 * We have to double the inner product sums, add in the
101 * outer product sums, propagate carries and convert
102 * to single precision.
103 */
104 {
105 register mp_digit *tmpb;
106
107 /* double first value, since the inner products are
108 * half of what they should be
109 */
110 W[0] += W[0] + W2[0];
111
112 tmpb = b->dp;
113 for (ix = 1; ix < newused; ix++) {
114 /* double/add next digit */
115 W[ix] += W[ix] + W2[ix];
116
117 /* propagate carry forwards [from the previous digit] */
118 W[ix] = W[ix] + (W[ix - 1] >> ((mp_word) DIGIT_BIT));
119
120 /* store the current digit now that the carry isn't
121 * needed
122 */
123 *tmpb++ = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK));
124 }
125 /* set the last value. Note even if the carry is zero
126 * this is required since the next step will not zero
127 * it if b originally had a value at b->dp[2*a.used]
128 */
129 *tmpb++ = (mp_digit) (W[(newused) - 1] & ((mp_word) MP_MASK));
130
131 /* clear high digits of b if there were any originally */
132 for (; ix < olduse; ix++) {
133 *tmpb++ = 0;
134 }
135 }
136
137 mp_clamp (b);
138 return MP_OKAY;
139 }