ecp_nistputil.c revision 296341
1/* crypto/ec/ecp_nistputil.c */
2/*
3 * Written by Bodo Moeller for the OpenSSL project.
4 */
5/* Copyright 2011 Google Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 *
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *     http://www.apache.org/licenses/LICENSE-2.0
13 *
14 *  Unless required by applicable law or agreed to in writing, software
15 *  distributed under the License is distributed on an "AS IS" BASIS,
16 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 *  See the License for the specific language governing permissions and
18 *  limitations under the License.
19 */
20
21#include <openssl/opensslconf.h>
22#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
23
24/*
25 * Common utility functions for ecp_nistp224.c, ecp_nistp256.c, ecp_nistp521.c.
26 */
27
28# include <stddef.h>
29# include "ec_lcl.h"
30
31/*
32 * Convert an array of points into affine coordinates. (If the point at
33 * infinity is found (Z = 0), it remains unchanged.) This function is
34 * essentially an equivalent to EC_POINTs_make_affine(), but works with the
35 * internal representation of points as used by ecp_nistp###.c rather than
36 * with (BIGNUM-based) EC_POINT data structures. point_array is the
37 * input/output buffer ('num' points in projective form, i.e. three
38 * coordinates each), based on an internal representation of field elements
39 * of size 'felem_size'. tmp_felems needs to point to a temporary array of
40 * 'num'+1 field elements for storage of intermediate values.
41 */
42void ec_GFp_nistp_points_make_affine_internal(size_t num, void *point_array,
43                                              size_t felem_size,
44                                              void *tmp_felems,
45                                              void (*felem_one) (void *out),
46                                              int (*felem_is_zero) (const void
47                                                                    *in),
48                                              void (*felem_assign) (void *out,
49                                                                    const void
50                                                                    *in),
51                                              void (*felem_square) (void *out,
52                                                                    const void
53                                                                    *in),
54                                              void (*felem_mul) (void *out,
55                                                                 const void
56                                                                 *in1,
57                                                                 const void
58                                                                 *in2),
59                                              void (*felem_inv) (void *out,
60                                                                 const void
61                                                                 *in),
62                                              void (*felem_contract) (void
63                                                                      *out,
64                                                                      const
65                                                                      void
66                                                                      *in))
67{
68    int i = 0;
69
70# define tmp_felem(I) (&((char *)tmp_felems)[(I) * felem_size])
71# define X(I) (&((char *)point_array)[3*(I) * felem_size])
72# define Y(I) (&((char *)point_array)[(3*(I) + 1) * felem_size])
73# define Z(I) (&((char *)point_array)[(3*(I) + 2) * felem_size])
74
75    if (!felem_is_zero(Z(0)))
76        felem_assign(tmp_felem(0), Z(0));
77    else
78        felem_one(tmp_felem(0));
79    for (i = 1; i < (int)num; i++) {
80        if (!felem_is_zero(Z(i)))
81            felem_mul(tmp_felem(i), tmp_felem(i - 1), Z(i));
82        else
83            felem_assign(tmp_felem(i), tmp_felem(i - 1));
84    }
85    /*
86     * Now each tmp_felem(i) is the product of Z(0) .. Z(i), skipping any
87     * zero-valued factors: if Z(i) = 0, we essentially pretend that Z(i) = 1
88     */
89
90    felem_inv(tmp_felem(num - 1), tmp_felem(num - 1));
91    for (i = num - 1; i >= 0; i--) {
92        if (i > 0)
93            /*
94             * tmp_felem(i-1) is the product of Z(0) .. Z(i-1), tmp_felem(i)
95             * is the inverse of the product of Z(0) .. Z(i)
96             */
97            /* 1/Z(i) */
98            felem_mul(tmp_felem(num), tmp_felem(i - 1), tmp_felem(i));
99        else
100            felem_assign(tmp_felem(num), tmp_felem(0)); /* 1/Z(0) */
101
102        if (!felem_is_zero(Z(i))) {
103            if (i > 0)
104                /*
105                 * For next iteration, replace tmp_felem(i-1) by its inverse
106                 */
107                felem_mul(tmp_felem(i - 1), tmp_felem(i), Z(i));
108
109            /*
110             * Convert point (X, Y, Z) into affine form (X/(Z^2), Y/(Z^3), 1)
111             */
112            felem_square(Z(i), tmp_felem(num)); /* 1/(Z^2) */
113            felem_mul(X(i), X(i), Z(i)); /* X/(Z^2) */
114            felem_mul(Z(i), Z(i), tmp_felem(num)); /* 1/(Z^3) */
115            felem_mul(Y(i), Y(i), Z(i)); /* Y/(Z^3) */
116            felem_contract(X(i), X(i));
117            felem_contract(Y(i), Y(i));
118            felem_one(Z(i));
119        } else {
120            if (i > 0)
121                /*
122                 * For next iteration, replace tmp_felem(i-1) by its inverse
123                 */
124                felem_assign(tmp_felem(i - 1), tmp_felem(i));
125        }
126    }
127}
128
129/*-
130 * This function looks at 5+1 scalar bits (5 current, 1 adjacent less
131 * significant bit), and recodes them into a signed digit for use in fast point
132 * multiplication: the use of signed rather than unsigned digits means that
133 * fewer points need to be precomputed, given that point inversion is easy
134 * (a precomputed point dP makes -dP available as well).
135 *
136 * BACKGROUND:
137 *
138 * Signed digits for multiplication were introduced by Booth ("A signed binary
139 * multiplication technique", Quart. Journ. Mech. and Applied Math., vol. IV,
140 * pt. 2 (1951), pp. 236-240), in that case for multiplication of integers.
141 * Booth's original encoding did not generally improve the density of nonzero
142 * digits over the binary representation, and was merely meant to simplify the
143 * handling of signed factors given in two's complement; but it has since been
144 * shown to be the basis of various signed-digit representations that do have
145 * further advantages, including the wNAF, using the following general approach:
146 *
147 * (1) Given a binary representation
148 *
149 *       b_k  ...  b_2  b_1  b_0,
150 *
151 *     of a nonnegative integer (b_k in {0, 1}), rewrite it in digits 0, 1, -1
152 *     by using bit-wise subtraction as follows:
153 *
154 *        b_k b_(k-1)  ...  b_2  b_1  b_0
155 *      -     b_k      ...  b_3  b_2  b_1  b_0
156 *       -------------------------------------
157 *        s_k b_(k-1)  ...  s_3  s_2  s_1  s_0
158 *
159 *     A left-shift followed by subtraction of the original value yields a new
160 *     representation of the same value, using signed bits s_i = b_(i+1) - b_i.
161 *     This representation from Booth's paper has since appeared in the
162 *     literature under a variety of different names including "reversed binary
163 *     form", "alternating greedy expansion", "mutual opposite form", and
164 *     "sign-alternating {+-1}-representation".
165 *
166 *     An interesting property is that among the nonzero bits, values 1 and -1
167 *     strictly alternate.
168 *
169 * (2) Various window schemes can be applied to the Booth representation of
170 *     integers: for example, right-to-left sliding windows yield the wNAF
171 *     (a signed-digit encoding independently discovered by various researchers
172 *     in the 1990s), and left-to-right sliding windows yield a left-to-right
173 *     equivalent of the wNAF (independently discovered by various researchers
174 *     around 2004).
175 *
176 * To prevent leaking information through side channels in point multiplication,
177 * we need to recode the given integer into a regular pattern: sliding windows
178 * as in wNAFs won't do, we need their fixed-window equivalent -- which is a few
179 * decades older: we'll be using the so-called "modified Booth encoding" due to
180 * MacSorley ("High-speed arithmetic in binary computers", Proc. IRE, vol. 49
181 * (1961), pp. 67-91), in a radix-2^5 setting.  That is, we always combine five
182 * signed bits into a signed digit:
183 *
184 *       s_(4j + 4) s_(4j + 3) s_(4j + 2) s_(4j + 1) s_(4j)
185 *
186 * The sign-alternating property implies that the resulting digit values are
187 * integers from -16 to 16.
188 *
189 * Of course, we don't actually need to compute the signed digits s_i as an
190 * intermediate step (that's just a nice way to see how this scheme relates
191 * to the wNAF): a direct computation obtains the recoded digit from the
192 * six bits b_(4j + 4) ... b_(4j - 1).
193 *
194 * This function takes those five bits as an integer (0 .. 63), writing the
195 * recoded digit to *sign (0 for positive, 1 for negative) and *digit (absolute
196 * value, in the range 0 .. 8).  Note that this integer essentially provides the
197 * input bits "shifted to the left" by one position: for example, the input to
198 * compute the least significant recoded digit, given that there's no bit b_-1,
199 * has to be b_4 b_3 b_2 b_1 b_0 0.
200 *
201 */
202void ec_GFp_nistp_recode_scalar_bits(unsigned char *sign,
203                                     unsigned char *digit, unsigned char in)
204{
205    unsigned char s, d;
206
207    s = ~((in >> 5) - 1);       /* sets all bits to MSB(in), 'in' seen as
208                                 * 6-bit value */
209    d = (1 << 6) - in - 1;
210    d = (d & s) | (in & ~s);
211    d = (d >> 1) + (d & 1);
212
213    *sign = s & 1;
214    *digit = d;
215}
216#else
217static void *dummy = &dummy;
218#endif
219