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 (at) 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 (at) cryptsoft.com). This product includes software written by Tim 52 * Hudson (tjh (at) 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 87 void 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|. 150 static 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 160 static 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 177 void 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