1238384Sjkim/* crypto/ec/ecp_nistputil.c */
2238384Sjkim/*
3238384Sjkim * Written by Bodo Moeller for the OpenSSL project.
4238384Sjkim */
5238384Sjkim/* Copyright 2011 Google Inc.
6238384Sjkim *
7238384Sjkim * Licensed under the Apache License, Version 2.0 (the "License");
8238384Sjkim *
9238384Sjkim * you may not use this file except in compliance with the License.
10238384Sjkim * You may obtain a copy of the License at
11238384Sjkim *
12238384Sjkim *     http://www.apache.org/licenses/LICENSE-2.0
13238384Sjkim *
14238384Sjkim *  Unless required by applicable law or agreed to in writing, software
15238384Sjkim *  distributed under the License is distributed on an "AS IS" BASIS,
16238384Sjkim *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17238384Sjkim *  See the License for the specific language governing permissions and
18238384Sjkim *  limitations under the License.
19238384Sjkim */
20238384Sjkim
21238384Sjkim#include <openssl/opensslconf.h>
22238384Sjkim#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
23238384Sjkim
24238384Sjkim/*
25238384Sjkim * Common utility functions for ecp_nistp224.c, ecp_nistp256.c, ecp_nistp521.c.
26238384Sjkim */
27238384Sjkim
28296341Sdelphij# include <stddef.h>
29296341Sdelphij# include "ec_lcl.h"
30238384Sjkim
31296341Sdelphij/*
32296341Sdelphij * Convert an array of points into affine coordinates. (If the point at
33296341Sdelphij * infinity is found (Z = 0), it remains unchanged.) This function is
34296341Sdelphij * essentially an equivalent to EC_POINTs_make_affine(), but works with the
35296341Sdelphij * internal representation of points as used by ecp_nistp###.c rather than
36296341Sdelphij * with (BIGNUM-based) EC_POINT data structures. point_array is the
37296341Sdelphij * input/output buffer ('num' points in projective form, i.e. three
38296341Sdelphij * coordinates each), based on an internal representation of field elements
39296341Sdelphij * of size 'felem_size'. tmp_felems needs to point to a temporary array of
40296341Sdelphij * 'num'+1 field elements for storage of intermediate values.
41238384Sjkim */
42238384Sjkimvoid ec_GFp_nistp_points_make_affine_internal(size_t num, void *point_array,
43296341Sdelphij                                              size_t felem_size,
44296341Sdelphij                                              void *tmp_felems,
45296341Sdelphij                                              void (*felem_one) (void *out),
46296341Sdelphij                                              int (*felem_is_zero) (const void
47296341Sdelphij                                                                    *in),
48296341Sdelphij                                              void (*felem_assign) (void *out,
49296341Sdelphij                                                                    const void
50296341Sdelphij                                                                    *in),
51296341Sdelphij                                              void (*felem_square) (void *out,
52296341Sdelphij                                                                    const void
53296341Sdelphij                                                                    *in),
54296341Sdelphij                                              void (*felem_mul) (void *out,
55296341Sdelphij                                                                 const void
56296341Sdelphij                                                                 *in1,
57296341Sdelphij                                                                 const void
58296341Sdelphij                                                                 *in2),
59296341Sdelphij                                              void (*felem_inv) (void *out,
60296341Sdelphij                                                                 const void
61296341Sdelphij                                                                 *in),
62296341Sdelphij                                              void (*felem_contract) (void
63296341Sdelphij                                                                      *out,
64296341Sdelphij                                                                      const
65296341Sdelphij                                                                      void
66296341Sdelphij                                                                      *in))
67296341Sdelphij{
68296341Sdelphij    int i = 0;
69238384Sjkim
70296341Sdelphij# define tmp_felem(I) (&((char *)tmp_felems)[(I) * felem_size])
71296341Sdelphij# define X(I) (&((char *)point_array)[3*(I) * felem_size])
72296341Sdelphij# define Y(I) (&((char *)point_array)[(3*(I) + 1) * felem_size])
73296341Sdelphij# define Z(I) (&((char *)point_array)[(3*(I) + 2) * felem_size])
74238384Sjkim
75296341Sdelphij    if (!felem_is_zero(Z(0)))
76296341Sdelphij        felem_assign(tmp_felem(0), Z(0));
77296341Sdelphij    else
78296341Sdelphij        felem_one(tmp_felem(0));
79296341Sdelphij    for (i = 1; i < (int)num; i++) {
80296341Sdelphij        if (!felem_is_zero(Z(i)))
81296341Sdelphij            felem_mul(tmp_felem(i), tmp_felem(i - 1), Z(i));
82296341Sdelphij        else
83296341Sdelphij            felem_assign(tmp_felem(i), tmp_felem(i - 1));
84296341Sdelphij    }
85296341Sdelphij    /*
86296341Sdelphij     * Now each tmp_felem(i) is the product of Z(0) .. Z(i), skipping any
87296341Sdelphij     * zero-valued factors: if Z(i) = 0, we essentially pretend that Z(i) = 1
88296341Sdelphij     */
89238384Sjkim
90296341Sdelphij    felem_inv(tmp_felem(num - 1), tmp_felem(num - 1));
91296341Sdelphij    for (i = num - 1; i >= 0; i--) {
92296341Sdelphij        if (i > 0)
93296341Sdelphij            /*
94296341Sdelphij             * tmp_felem(i-1) is the product of Z(0) .. Z(i-1), tmp_felem(i)
95296341Sdelphij             * is the inverse of the product of Z(0) .. Z(i)
96296341Sdelphij             */
97296341Sdelphij            /* 1/Z(i) */
98296341Sdelphij            felem_mul(tmp_felem(num), tmp_felem(i - 1), tmp_felem(i));
99296341Sdelphij        else
100296341Sdelphij            felem_assign(tmp_felem(num), tmp_felem(0)); /* 1/Z(0) */
101238384Sjkim
102296341Sdelphij        if (!felem_is_zero(Z(i))) {
103296341Sdelphij            if (i > 0)
104296341Sdelphij                /*
105296341Sdelphij                 * For next iteration, replace tmp_felem(i-1) by its inverse
106296341Sdelphij                 */
107296341Sdelphij                felem_mul(tmp_felem(i - 1), tmp_felem(i), Z(i));
108238384Sjkim
109296341Sdelphij            /*
110296341Sdelphij             * Convert point (X, Y, Z) into affine form (X/(Z^2), Y/(Z^3), 1)
111296341Sdelphij             */
112296341Sdelphij            felem_square(Z(i), tmp_felem(num)); /* 1/(Z^2) */
113296341Sdelphij            felem_mul(X(i), X(i), Z(i)); /* X/(Z^2) */
114296341Sdelphij            felem_mul(Z(i), Z(i), tmp_felem(num)); /* 1/(Z^3) */
115296341Sdelphij            felem_mul(Y(i), Y(i), Z(i)); /* Y/(Z^3) */
116296341Sdelphij            felem_contract(X(i), X(i));
117296341Sdelphij            felem_contract(Y(i), Y(i));
118296341Sdelphij            felem_one(Z(i));
119296341Sdelphij        } else {
120296341Sdelphij            if (i > 0)
121296341Sdelphij                /*
122296341Sdelphij                 * For next iteration, replace tmp_felem(i-1) by its inverse
123296341Sdelphij                 */
124296341Sdelphij                felem_assign(tmp_felem(i - 1), tmp_felem(i));
125296341Sdelphij        }
126296341Sdelphij    }
127296341Sdelphij}
128238384Sjkim
129296341Sdelphij/*-
130238384Sjkim * This function looks at 5+1 scalar bits (5 current, 1 adjacent less
131238384Sjkim * significant bit), and recodes them into a signed digit for use in fast point
132238384Sjkim * multiplication: the use of signed rather than unsigned digits means that
133238384Sjkim * fewer points need to be precomputed, given that point inversion is easy
134238384Sjkim * (a precomputed point dP makes -dP available as well).
135238384Sjkim *
136238384Sjkim * BACKGROUND:
137238384Sjkim *
138238384Sjkim * Signed digits for multiplication were introduced by Booth ("A signed binary
139238384Sjkim * multiplication technique", Quart. Journ. Mech. and Applied Math., vol. IV,
140238384Sjkim * pt. 2 (1951), pp. 236-240), in that case for multiplication of integers.
141238384Sjkim * Booth's original encoding did not generally improve the density of nonzero
142238384Sjkim * digits over the binary representation, and was merely meant to simplify the
143238384Sjkim * handling of signed factors given in two's complement; but it has since been
144238384Sjkim * shown to be the basis of various signed-digit representations that do have
145238384Sjkim * further advantages, including the wNAF, using the following general approach:
146238384Sjkim *
147238384Sjkim * (1) Given a binary representation
148238384Sjkim *
149238384Sjkim *       b_k  ...  b_2  b_1  b_0,
150238384Sjkim *
151238384Sjkim *     of a nonnegative integer (b_k in {0, 1}), rewrite it in digits 0, 1, -1
152238384Sjkim *     by using bit-wise subtraction as follows:
153238384Sjkim *
154238384Sjkim *        b_k b_(k-1)  ...  b_2  b_1  b_0
155238384Sjkim *      -     b_k      ...  b_3  b_2  b_1  b_0
156238384Sjkim *       -------------------------------------
157238384Sjkim *        s_k b_(k-1)  ...  s_3  s_2  s_1  s_0
158238384Sjkim *
159238384Sjkim *     A left-shift followed by subtraction of the original value yields a new
160238384Sjkim *     representation of the same value, using signed bits s_i = b_(i+1) - b_i.
161238384Sjkim *     This representation from Booth's paper has since appeared in the
162238384Sjkim *     literature under a variety of different names including "reversed binary
163238384Sjkim *     form", "alternating greedy expansion", "mutual opposite form", and
164238384Sjkim *     "sign-alternating {+-1}-representation".
165238384Sjkim *
166238384Sjkim *     An interesting property is that among the nonzero bits, values 1 and -1
167238384Sjkim *     strictly alternate.
168238384Sjkim *
169238384Sjkim * (2) Various window schemes can be applied to the Booth representation of
170238384Sjkim *     integers: for example, right-to-left sliding windows yield the wNAF
171238384Sjkim *     (a signed-digit encoding independently discovered by various researchers
172238384Sjkim *     in the 1990s), and left-to-right sliding windows yield a left-to-right
173238384Sjkim *     equivalent of the wNAF (independently discovered by various researchers
174238384Sjkim *     around 2004).
175238384Sjkim *
176238384Sjkim * To prevent leaking information through side channels in point multiplication,
177238384Sjkim * we need to recode the given integer into a regular pattern: sliding windows
178238384Sjkim * as in wNAFs won't do, we need their fixed-window equivalent -- which is a few
179238384Sjkim * decades older: we'll be using the so-called "modified Booth encoding" due to
180238384Sjkim * MacSorley ("High-speed arithmetic in binary computers", Proc. IRE, vol. 49
181238384Sjkim * (1961), pp. 67-91), in a radix-2^5 setting.  That is, we always combine five
182238384Sjkim * signed bits into a signed digit:
183238384Sjkim *
184238384Sjkim *       s_(4j + 4) s_(4j + 3) s_(4j + 2) s_(4j + 1) s_(4j)
185238384Sjkim *
186238384Sjkim * The sign-alternating property implies that the resulting digit values are
187238384Sjkim * integers from -16 to 16.
188238384Sjkim *
189238384Sjkim * Of course, we don't actually need to compute the signed digits s_i as an
190238384Sjkim * intermediate step (that's just a nice way to see how this scheme relates
191238384Sjkim * to the wNAF): a direct computation obtains the recoded digit from the
192238384Sjkim * six bits b_(4j + 4) ... b_(4j - 1).
193238384Sjkim *
194238384Sjkim * This function takes those five bits as an integer (0 .. 63), writing the
195238384Sjkim * recoded digit to *sign (0 for positive, 1 for negative) and *digit (absolute
196238384Sjkim * value, in the range 0 .. 8).  Note that this integer essentially provides the
197238384Sjkim * input bits "shifted to the left" by one position: for example, the input to
198238384Sjkim * compute the least significant recoded digit, given that there's no bit b_-1,
199238384Sjkim * has to be b_4 b_3 b_2 b_1 b_0 0.
200238384Sjkim *
201238384Sjkim */
202296341Sdelphijvoid ec_GFp_nistp_recode_scalar_bits(unsigned char *sign,
203296341Sdelphij                                     unsigned char *digit, unsigned char in)
204296341Sdelphij{
205296341Sdelphij    unsigned char s, d;
206238384Sjkim
207296341Sdelphij    s = ~((in >> 5) - 1);       /* sets all bits to MSB(in), 'in' seen as
208296341Sdelphij                                 * 6-bit value */
209296341Sdelphij    d = (1 << 6) - in - 1;
210296341Sdelphij    d = (d & s) | (in & ~s);
211296341Sdelphij    d = (d >> 1) + (d & 1);
212238384Sjkim
213296341Sdelphij    *sign = s & 1;
214296341Sdelphij    *digit = d;
215296341Sdelphij}
216238384Sjkim#else
217296341Sdelphijstatic void *dummy = &dummy;
218238384Sjkim#endif
219