Coverage Report

Created: 2022-11-30 06:20

/src/openssl/crypto/ec/ecp_nistputil.c
Line
Count
Source (jump to first uncovered line)
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
 */
42
void 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
0
{
68
0
    int i = 0;
69
70
0
# define tmp_felem(I) (&((char *)tmp_felems)[(I) * felem_size])
71
0
# define X(I) (&((char *)point_array)[3*(I) * felem_size])
72
0
# define Y(I) (&((char *)point_array)[(3*(I) + 1) * felem_size])
73
0
# define Z(I) (&((char *)point_array)[(3*(I) + 2) * felem_size])
74
75
0
    if (!felem_is_zero(Z(0)))
76
0
        felem_assign(tmp_felem(0), Z(0));
77
0
    else
78
0
        felem_one(tmp_felem(0));
79
0
    for (i = 1; i < (int)num; i++) {
80
0
        if (!felem_is_zero(Z(i)))
81
0
            felem_mul(tmp_felem(i), tmp_felem(i - 1), Z(i));
82
0
        else
83
0
            felem_assign(tmp_felem(i), tmp_felem(i - 1));
84
0
    }
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
0
    felem_inv(tmp_felem(num - 1), tmp_felem(num - 1));
91
0
    for (i = num - 1; i >= 0; i--) {
92
0
        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
0
            felem_mul(tmp_felem(num), tmp_felem(i - 1), tmp_felem(i));
99
0
        else
100
0
            felem_assign(tmp_felem(num), tmp_felem(0)); /* 1/Z(0) */
101
102
0
        if (!felem_is_zero(Z(i))) {
103
0
            if (i > 0)
104
                /*
105
                 * For next iteration, replace tmp_felem(i-1) by its inverse
106
                 */
107
0
                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
0
            felem_square(Z(i), tmp_felem(num)); /* 1/(Z^2) */
113
0
            felem_mul(X(i), X(i), Z(i)); /* X/(Z^2) */
114
0
            felem_mul(Z(i), Z(i), tmp_felem(num)); /* 1/(Z^3) */
115
0
            felem_mul(Y(i), Y(i), Z(i)); /* Y/(Z^3) */
116
0
            felem_contract(X(i), X(i));
117
0
            felem_contract(Y(i), Y(i));
118
0
            felem_one(Z(i));
119
0
        } else {
120
0
            if (i > 0)
121
                /*
122
                 * For next iteration, replace tmp_felem(i-1) by its inverse
123
                 */
124
0
                felem_assign(tmp_felem(i - 1), tmp_felem(i));
125
0
        }
126
0
    }
127
0
}
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
 */
202
void ec_GFp_nistp_recode_scalar_bits(unsigned char *sign,
203
                                     unsigned char *digit, unsigned char in)
204
0
{
205
0
    unsigned char s, d;
206
207
0
    s = ~((in >> 5) - 1);       /* sets all bits to MSB(in), 'in' seen as
208
                                 * 6-bit value */
209
0
    d = (1 << 6) - in - 1;
210
0
    d = (d & s) | (in & ~s);
211
0
    d = (d >> 1) + (d & 1);
212
213
0
    *sign = s & 1;
214
0
    *digit = d;
215
0
}
216
#else
217
static void *dummy = &dummy;
218
#endif