1/* Originally written by Bodo Moeller for the OpenSSL project.
2 * ====================================================================
3 * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * 3. All advertising materials mentioning features or use of this
18 * software must display the following acknowledgment:
19 * "This product includes software developed by the OpenSSL Project
20 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
21 *
22 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23 * endorse or promote products derived from this software without
24 * prior written permission. For written permission, please contact
25 * openssl-core@openssl.org.
26 *
27 * 5. Products derived from this software may not be called "OpenSSL"
28 * nor may "OpenSSL" appear in their names without prior written
29 * permission of the OpenSSL Project.
30 *
31 * 6. Redistributions of any form whatsoever must retain the following
32 * acknowledgment:
33 * "This product includes software developed by the OpenSSL Project
34 * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
35 *
36 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47 * OF THE POSSIBILITY OF SUCH DAMAGE.
48 * ====================================================================
49 *
50 * This product includes cryptographic software written by Eric Young
51 * (eay@cryptsoft.com). This product includes software written by Tim
52 * Hudson (tjh@cryptsoft.com).
53 *
54 */
55/* ====================================================================
56 * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
57 *
58 * Portions of the attached software ("Contribution") are developed by
59 * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
60 *
61 * The Contribution is licensed pursuant to the OpenSSL open source
62 * license provided above.
63 *
64 * The elliptic curve binary polynomial software is originally written by
65 * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
66 * Laboratories. */
67
68#include <openssl/ec.h>
69
70#include <assert.h>
71#include <string.h>
72
73#include <openssl/bn.h>
74#include <openssl/err.h>
75#include <openssl/thread.h>
76
77#include "internal.h"
78#include "../bn/internal.h"
79#include "../../internal.h"
80
81
82// This file implements the wNAF-based interleaving multi-exponentiation method
83// at:
84// http://link.springer.com/chapter/10.1007%2F3-540-45537-X_13
85// http://www.bmoeller.de/pdf/TI-01-08.multiexp.pdf
86
87void ec_compute_wNAF(const EC_GROUP *group, int8_t *out,
88 const EC_SCALAR *scalar, size_t bits, int w) {
89 // 'int8_t' can represent integers with absolute values less than 2^7.
90 assert(0 < w && w <= 7);
91 assert(bits != 0);
92 int bit = 1 << w; // 2^w, at most 128
93 int next_bit = bit << 1; // 2^(w+1), at most 256
94 int mask = next_bit - 1; // at most 255
95
96 int window_val = scalar->words[0] & mask;
97 for (size_t j = 0; j < bits + 1; j++) {
98 assert(0 <= window_val && window_val <= next_bit);
99 int digit = 0;
100 if (window_val & 1) {
101 assert(0 < window_val && window_val < next_bit);
102 if (window_val & bit) {
103 digit = window_val - next_bit;
104 // We know -next_bit < digit < 0 and window_val - digit = next_bit.
105
106 // modified wNAF
107 if (j + w + 1 >= bits) {
108 // special case for generating modified wNAFs:
109 // no new bits will be added into window_val,
110 // so using a positive digit here will decrease
111 // the total length of the representation
112
113 digit = window_val & (mask >> 1);
114 // We know 0 < digit < bit and window_val - digit = bit.
115 }
116 } else {
117 digit = window_val;
118 // We know 0 < digit < bit and window_val - digit = 0.
119 }
120
121 window_val -= digit;
122
123 // Now window_val is 0 or 2^(w+1) in standard wNAF generation.
124 // For modified window NAFs, it may also be 2^w.
125 //
126 // See the comments above for the derivation of each of these bounds.
127 assert(window_val == 0 || window_val == next_bit || window_val == bit);
128 assert(-bit < digit && digit < bit);
129
130 // window_val was odd, so digit is also odd.
131 assert(digit & 1);
132 }
133
134 out[j] = digit;
135
136 // Incorporate the next bit. Previously, |window_val| <= |next_bit|, so if
137 // we shift and add at most one copy of |bit|, this will continue to hold
138 // afterwards.
139 window_val >>= 1;
140 window_val +=
141 bit * bn_is_bit_set_words(scalar->words, group->order.width, j + w + 1);
142 assert(window_val <= next_bit);
143 }
144
145 // bits + 1 entries should be sufficient to consume all bits.
146 assert(window_val == 0);
147}
148
149// compute_precomp sets |out[i]| to (2*i+1)*p, for i from 0 to |len|.
150static void compute_precomp(const EC_GROUP *group, EC_RAW_POINT *out,
151 const EC_RAW_POINT *p, size_t len) {
152 ec_GFp_simple_point_copy(&out[0], p);
153 EC_RAW_POINT two_p;
154 ec_GFp_mont_dbl(group, &two_p, p);
155 for (size_t i = 1; i < len; i++) {
156 ec_GFp_mont_add(group, &out[i], &out[i - 1], &two_p);
157 }
158}
159
160static void lookup_precomp(const EC_GROUP *group, EC_RAW_POINT *out,
161 const EC_RAW_POINT *precomp, int digit) {
162 if (digit < 0) {
163 digit = -digit;
164 ec_GFp_simple_point_copy(out, &precomp[digit >> 1]);
165 ec_GFp_simple_invert(group, out);
166 } else {
167 ec_GFp_simple_point_copy(out, &precomp[digit >> 1]);
168 }
169}
170
171// EC_WNAF_WINDOW_BITS is the window size to use for |ec_GFp_mont_mul_public|.
172#define EC_WNAF_WINDOW_BITS 4
173
174// EC_WNAF_TABLE_SIZE is the table size to use for |ec_GFp_mont_mul_public|.
175#define EC_WNAF_TABLE_SIZE (1 << (EC_WNAF_WINDOW_BITS - 1))
176
177void ec_GFp_mont_mul_public(const EC_GROUP *group, EC_RAW_POINT *r,
178 const EC_SCALAR *g_scalar, const EC_RAW_POINT *p,
179 const EC_SCALAR *p_scalar) {
180 size_t bits = BN_num_bits(&group->order);
181 size_t wNAF_len = bits + 1;
182
183 int8_t g_wNAF[EC_MAX_BYTES * 8 + 1];
184 EC_RAW_POINT g_precomp[EC_WNAF_TABLE_SIZE];
185 assert(wNAF_len <= OPENSSL_ARRAY_SIZE(g_wNAF));
186 const EC_RAW_POINT *g = &group->generator->raw;
187 ec_compute_wNAF(group, g_wNAF, g_scalar, bits, EC_WNAF_WINDOW_BITS);
188 compute_precomp(group, g_precomp, g, EC_WNAF_TABLE_SIZE);
189
190 int8_t p_wNAF[EC_MAX_BYTES * 8 + 1];
191 EC_RAW_POINT p_precomp[EC_WNAF_TABLE_SIZE];
192 assert(wNAF_len <= OPENSSL_ARRAY_SIZE(p_wNAF));
193 ec_compute_wNAF(group, p_wNAF, p_scalar, bits, EC_WNAF_WINDOW_BITS);
194 compute_precomp(group, p_precomp, p, EC_WNAF_TABLE_SIZE);
195
196 EC_RAW_POINT tmp;
197 int r_is_at_infinity = 1;
198 for (size_t k = wNAF_len - 1; k < wNAF_len; k--) {
199 if (!r_is_at_infinity) {
200 ec_GFp_mont_dbl(group, r, r);
201 }
202
203 if (g_wNAF[k] != 0) {
204 lookup_precomp(group, &tmp, g_precomp, g_wNAF[k]);
205 if (r_is_at_infinity) {
206 ec_GFp_simple_point_copy(r, &tmp);
207 r_is_at_infinity = 0;
208 } else {
209 ec_GFp_mont_add(group, r, r, &tmp);
210 }
211 }
212
213 if (p_wNAF[k] != 0) {
214 lookup_precomp(group, &tmp, p_precomp, p_wNAF[k]);
215 if (r_is_at_infinity) {
216 ec_GFp_simple_point_copy(r, &tmp);
217 r_is_at_infinity = 0;
218 } else {
219 ec_GFp_mont_add(group, r, r, &tmp);
220 }
221 }
222 }
223
224 if (r_is_at_infinity) {
225 ec_GFp_simple_point_set_to_infinity(group, r);
226 }
227}
228