diff options
-rw-r--r-- | src/lib/libcrypto/ec/ec_mult.c | 225 |
1 files changed, 80 insertions, 145 deletions
diff --git a/src/lib/libcrypto/ec/ec_mult.c b/src/lib/libcrypto/ec/ec_mult.c index 1b7eb4ec1b..c119410e4a 100644 --- a/src/lib/libcrypto/ec/ec_mult.c +++ b/src/lib/libcrypto/ec/ec_mult.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ec_mult.c,v 1.43 2024/11/22 15:21:14 tb Exp $ */ | 1 | /* $OpenBSD: ec_mult.c,v 1.44 2024/11/22 16:17:36 tb Exp $ */ |
2 | /* | 2 | /* |
3 | * Originally written by Bodo Moeller and Nils Larsch for the OpenSSL project. | 3 | * Originally written by Bodo Moeller and Nils Larsch for the OpenSSL project. |
4 | */ | 4 | */ |
@@ -70,154 +70,95 @@ | |||
70 | #include "bn_local.h" | 70 | #include "bn_local.h" |
71 | #include "ec_local.h" | 71 | #include "ec_local.h" |
72 | 72 | ||
73 | /* | 73 | static int |
74 | * This file implements the wNAF-based interleaving multi-exponentation method | 74 | ec_window_bits(const BIGNUM *bn) |
75 | * (<URL:http://www.informatik.tu-darmstadt.de/TI/Mitarbeiter/moeller.html#multiexp>); | 75 | { |
76 | * for multiplication with precomputation, we use wNAF splitting | 76 | int bits = BN_num_bits(bn); |
77 | * (<URL:http://www.informatik.tu-darmstadt.de/TI/Mitarbeiter/moeller.html#fastexp>). | 77 | |
78 | */ | 78 | if (bits >= 2000) |
79 | return 6; | ||
80 | if (bits >= 800) | ||
81 | return 5; | ||
82 | if (bits >= 300) | ||
83 | return 4; | ||
84 | if (bits >= 70) | ||
85 | return 3; | ||
86 | if (bits >= 20) | ||
87 | return 2; | ||
88 | |||
89 | return 1; | ||
90 | } | ||
79 | 91 | ||
80 | /* Determine the modified width-(w+1) Non-Adjacent Form (wNAF) of 'scalar'. | 92 | static int |
81 | * This is an array r[] of values that are either zero or odd with an | 93 | ec_compute_wNAF(const BIGNUM *bn, signed char **out_wNAF, size_t *out_wNAF_len, |
82 | * absolute value less than 2^w satisfying | 94 | size_t *out_len) |
83 | * scalar = \sum_j r[j]*2^j | ||
84 | * where at most one of any w+1 consecutive digits is non-zero | ||
85 | * with the exception that the most significant digit may be only | ||
86 | * w-1 zeros away from that next non-zero digit. | ||
87 | */ | ||
88 | static signed char * | ||
89 | compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) | ||
90 | { | 95 | { |
91 | int window_val; | 96 | signed char *wNAF = NULL; |
92 | int ok = 0; | 97 | size_t wNAF_len = 1, len = 1; |
93 | signed char *r = NULL; | 98 | int digit, bit, next, mask, sign, wbits, window; |
94 | int sign = 1; | 99 | size_t i; |
95 | int bit, next_bit, mask; | 100 | int ret = 0; |
96 | size_t len = 0, j; | 101 | |
97 | 102 | if (BN_is_zero(bn)) { | |
98 | if (BN_is_zero(scalar)) { | 103 | if ((wNAF = calloc(1, 1)) == NULL) { |
99 | r = malloc(1); | ||
100 | if (!r) { | ||
101 | ECerror(ERR_R_MALLOC_FAILURE); | 104 | ECerror(ERR_R_MALLOC_FAILURE); |
102 | goto err; | 105 | goto err; |
103 | } | 106 | } |
104 | r[0] = 0; | ||
105 | *ret_len = 1; | ||
106 | return r; | ||
107 | } | ||
108 | if (w <= 0 || w > 7) { | ||
109 | /* 'signed char' can represent integers with | ||
110 | * absolute values less than 2^7 */ | ||
111 | ECerror(ERR_R_INTERNAL_ERROR); | ||
112 | goto err; | ||
113 | } | ||
114 | bit = 1 << w; /* at most 128 */ | ||
115 | next_bit = bit << 1; /* at most 256 */ | ||
116 | mask = next_bit - 1; /* at most 255 */ | ||
117 | 107 | ||
118 | if (BN_is_negative(scalar)) { | 108 | goto done; |
119 | sign = -1; | ||
120 | } | 109 | } |
121 | if (scalar->d == NULL || scalar->top == 0) { | 110 | |
122 | ECerror(ERR_R_INTERNAL_ERROR); | 111 | wNAF_len = BN_num_bits(bn); |
123 | goto err; | 112 | if ((wNAF = calloc(1, wNAF_len + 1)) == NULL) { |
124 | } | ||
125 | len = BN_num_bits(scalar); | ||
126 | r = malloc(len + 1); /* modified wNAF may be one digit longer than | ||
127 | * binary representation (*ret_len will be | ||
128 | * set to the actual length, i.e. at most | ||
129 | * BN_num_bits(scalar) + 1) */ | ||
130 | if (r == NULL) { | ||
131 | ECerror(ERR_R_MALLOC_FAILURE); | 113 | ECerror(ERR_R_MALLOC_FAILURE); |
132 | goto err; | 114 | goto err; |
133 | } | 115 | } |
134 | window_val = scalar->d[0] & mask; | ||
135 | j = 0; | ||
136 | while ((window_val != 0) || (j + w + 1 < len)) { | ||
137 | /* if j+w+1 >= len, window_val will not increase */ | ||
138 | int digit = 0; | ||
139 | |||
140 | /* 0 <= window_val <= 2^(w+1) */ | ||
141 | if (window_val & 1) { | ||
142 | /* 0 < window_val < 2^(w+1) */ | ||
143 | if (window_val & bit) { | ||
144 | digit = window_val - next_bit; /* -2^w < digit < 0 */ | ||
145 | |||
146 | #if 1 /* modified wNAF */ | ||
147 | if (j + w + 1 >= len) { | ||
148 | /* | ||
149 | * special case for generating | ||
150 | * modified wNAFs: no new bits will | ||
151 | * be added into window_val, so using | ||
152 | * a positive digit here will | ||
153 | * decrease the total length of the | ||
154 | * representation | ||
155 | */ | ||
156 | |||
157 | digit = window_val & (mask >> 1); /* 0 < digit < 2^w */ | ||
158 | } | ||
159 | #endif | ||
160 | } else { | ||
161 | digit = window_val; /* 0 < digit < 2^w */ | ||
162 | } | ||
163 | 116 | ||
164 | if (digit <= -bit || digit >= bit || !(digit & 1)) { | 117 | wbits = ec_window_bits(bn); |
165 | ECerror(ERR_R_INTERNAL_ERROR); | 118 | len = 1 << (wbits - 1); |
166 | goto err; | ||
167 | } | ||
168 | window_val -= digit; | ||
169 | |||
170 | /* | ||
171 | * now window_val is 0 or 2^(w+1) in standard wNAF | ||
172 | * generation; for modified window NAFs, it may also | ||
173 | * be 2^w | ||
174 | */ | ||
175 | if (window_val != 0 && window_val != next_bit && window_val != bit) { | ||
176 | ECerror(ERR_R_INTERNAL_ERROR); | ||
177 | goto err; | ||
178 | } | ||
179 | } | ||
180 | r[j++] = sign * digit; | ||
181 | 119 | ||
182 | window_val >>= 1; | 120 | bit = 1 << wbits; |
183 | window_val += bit * BN_is_bit_set(scalar, j + w); | 121 | next = bit << 1; |
122 | mask = next - 1; | ||
184 | 123 | ||
185 | if (window_val > next_bit) { | 124 | sign = BN_is_negative(bn) ? -1 : 1; |
186 | ECerror(ERR_R_INTERNAL_ERROR); | 125 | |
187 | goto err; | 126 | window = bn->d[0] & mask; |
127 | i = 0; | ||
128 | while (window != 0 || i + wbits + 1 < wNAF_len) { | ||
129 | digit = 0; | ||
130 | |||
131 | if ((window & 1) != 0) { | ||
132 | digit = window; | ||
133 | if ((window & bit) != 0) { | ||
134 | digit = window - next; | ||
135 | |||
136 | if (i + wbits + 1 >= wNAF_len) | ||
137 | digit = window & (mask >> 1); | ||
138 | } | ||
139 | window -= digit; | ||
188 | } | 140 | } |
189 | } | ||
190 | 141 | ||
191 | if (j > len + 1) { | 142 | wNAF[i++] = sign * digit; |
192 | ECerror(ERR_R_INTERNAL_ERROR); | 143 | window >>= 1; |
193 | goto err; | 144 | window += bit * BN_is_bit_set(bn, i + wbits); |
194 | } | 145 | } |
195 | len = j; | ||
196 | ok = 1; | ||
197 | 146 | ||
198 | err: | 147 | wNAF_len = i; |
199 | if (!ok) { | ||
200 | free(r); | ||
201 | r = NULL; | ||
202 | } | ||
203 | if (ok) | ||
204 | *ret_len = len; | ||
205 | return r; | ||
206 | } | ||
207 | 148 | ||
149 | done: | ||
150 | *out_wNAF = wNAF; | ||
151 | wNAF = NULL; | ||
152 | *out_wNAF_len = wNAF_len; | ||
153 | *out_len = len; | ||
208 | 154 | ||
209 | /* TODO: table should be optimised for the wNAF-based implementation, | 155 | ret = 1; |
210 | * sometimes smaller windows will give better performance | 156 | |
211 | * (thus the boundaries should be increased) | 157 | err: |
212 | */ | 158 | free(wNAF); |
213 | #define EC_window_bits_for_scalar_size(b) \ | 159 | |
214 | ((size_t) \ | 160 | return ret; |
215 | ((b) >= 2000 ? 6 : \ | 161 | } |
216 | (b) >= 800 ? 5 : \ | ||
217 | (b) >= 300 ? 4 : \ | ||
218 | (b) >= 70 ? 3 : \ | ||
219 | (b) >= 20 ? 2 : \ | ||
220 | 1)) | ||
221 | 162 | ||
222 | static int | 163 | static int |
223 | ec_compute_odd_multiples(const EC_GROUP *group, const EC_POINT *point, | 164 | ec_compute_odd_multiples(const EC_GROUP *group, const EC_POINT *point, |
@@ -270,8 +211,8 @@ ec_wNAF_precompute(const EC_GROUP *group, const BIGNUM *m, const EC_POINT *point | |||
270 | EC_POINT **val = NULL; | 211 | EC_POINT **val = NULL; |
271 | size_t val_len = 0; | 212 | size_t val_len = 0; |
272 | const EC_POINT *generator; | 213 | const EC_POINT *generator; |
273 | size_t wsize[2] = { 0 }; | 214 | size_t len[2] = { 0 }; |
274 | size_t i, len0, len1; | 215 | size_t i; |
275 | int ret = 0; | 216 | int ret = 0; |
276 | 217 | ||
277 | *out_val = NULL; | 218 | *out_val = NULL; |
@@ -282,29 +223,23 @@ ec_wNAF_precompute(const EC_GROUP *group, const BIGNUM *m, const EC_POINT *point | |||
282 | goto err; | 223 | goto err; |
283 | } | 224 | } |
284 | 225 | ||
285 | wsize[0] = EC_window_bits_for_scalar_size(BN_num_bits(m)); | 226 | if (!ec_compute_wNAF(m, &wNAF[0], &wNAF_len[0], &len[0])) |
286 | if ((wNAF[0] = compute_wNAF(m, wsize[0], &wNAF_len[0])) == NULL) | ||
287 | goto err; | 227 | goto err; |
288 | 228 | if (!ec_compute_wNAF(n, &wNAF[1], &wNAF_len[1], &len[1])) | |
289 | wsize[1] = EC_window_bits_for_scalar_size(BN_num_bits(n)); | ||
290 | if ((wNAF[1] = compute_wNAF(n, wsize[1], &wNAF_len[1])) == NULL) | ||
291 | goto err; | 229 | goto err; |
292 | 230 | ||
293 | len0 = 1 << (wsize[0] - 1); | 231 | if ((val = calloc(len[0] + len[1], sizeof(*val))) == NULL) { |
294 | len1 = 1 << (wsize[1] - 1); | ||
295 | |||
296 | if ((val = calloc(len0 + len1, sizeof(*val))) == NULL) { | ||
297 | ECerror(ERR_R_MALLOC_FAILURE); | 232 | ECerror(ERR_R_MALLOC_FAILURE); |
298 | goto err; | 233 | goto err; |
299 | } | 234 | } |
300 | val_len = len0 + len1; | 235 | val_len = len[0] + len[1]; |
301 | 236 | ||
302 | row[0] = &val[0]; | 237 | row[0] = &val[0]; |
303 | row[1] = &val[len0]; | 238 | row[1] = &val[len[0]]; |
304 | 239 | ||
305 | if (!ec_compute_odd_multiples(group, generator, row[0], len0, ctx)) | 240 | if (!ec_compute_odd_multiples(group, generator, row[0], len[0], ctx)) |
306 | goto err; | 241 | goto err; |
307 | if (!ec_compute_odd_multiples(group, point, row[1], len1, ctx)) | 242 | if (!ec_compute_odd_multiples(group, point, row[1], len[1], ctx)) |
308 | goto err; | 243 | goto err; |
309 | 244 | ||
310 | if (!EC_POINTs_make_affine(group, val_len, val, ctx)) | 245 | if (!EC_POINTs_make_affine(group, val_len, val, ctx)) |