diff options
author | jsing <> | 2023-02-22 05:25:47 +0000 |
---|---|---|
committer | jsing <> | 2023-02-22 05:25:47 +0000 |
commit | 12aca8f870a07f30e989b326c4371746b668dc5f (patch) | |
tree | 5f5afd57f49d799d6b6009aa89d682b6e78ee6a2 | |
parent | d8461c9d54c6b42b4f063da326afcf700ebcbe4f (diff) | |
download | openbsd-12aca8f870a07f30e989b326c4371746b668dc5f.tar.gz openbsd-12aca8f870a07f30e989b326c4371746b668dc5f.tar.bz2 openbsd-12aca8f870a07f30e989b326c4371746b668dc5f.zip |
Rewrite and simplify BN_MONT_CTX_set()
OpenSSL commit 4d524040bc8 changed BN_MONT_CTX_set() so that it computed
a 64 bit N^-1 on both BN_BITS2 == 32 and BN_BITS2 == 64 platforms. However,
the way in which this was done was to duplicate half the code and wrap it
in #ifdef.
Rewrite this code to use a single code path on all platforms, with #ifdef
being limited to setting an additional word in the temporary N and storing
the result on BN_BITS2 == 32 platforms. Also remove stack based BIGNUM in
favour of using the already present BN_CTX.
ok tb@
-rw-r--r-- | src/lib/libcrypto/bn/bn_local.h | 15 | ||||
-rw-r--r-- | src/lib/libcrypto/bn/bn_mont.c | 159 |
2 files changed, 76 insertions, 98 deletions
diff --git a/src/lib/libcrypto/bn/bn_local.h b/src/lib/libcrypto/bn/bn_local.h index c763890695..35e9073e2d 100644 --- a/src/lib/libcrypto/bn/bn_local.h +++ b/src/lib/libcrypto/bn/bn_local.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: bn_local.h,v 1.14 2023/02/21 05:58:08 jsing Exp $ */ | 1 | /* $OpenBSD: bn_local.h,v 1.15 2023/02/22 05:25:47 jsing Exp $ */ |
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 | * All rights reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
@@ -127,13 +127,14 @@ struct bignum_st { | |||
127 | int flags; | 127 | int flags; |
128 | }; | 128 | }; |
129 | 129 | ||
130 | /* Used for montgomery multiplication */ | ||
131 | struct bn_mont_ctx_st { | 130 | struct bn_mont_ctx_st { |
132 | int ri; /* number of bits in R */ | 131 | int ri; /* Number of bits in R */ |
133 | BIGNUM RR; /* used to convert to montgomery form */ | 132 | BIGNUM RR; /* Used to convert to Montgomery form */ |
134 | BIGNUM N; /* The modulus */ | 133 | BIGNUM N; /* Modulus */ |
135 | BN_ULONG n0[2];/* least significant word(s) of Ni; R*(1/R mod N) - N*Ni = 1 | 134 | |
136 | (type changed with 0.9.9, was "BN_ULONG n0;" before) */ | 135 | /* Least significant word(s) of Ni; R*(1/R mod N) - N*Ni = 1 */ |
136 | BN_ULONG n0[2]; | ||
137 | |||
137 | int flags; | 138 | int flags; |
138 | }; | 139 | }; |
139 | 140 | ||
diff --git a/src/lib/libcrypto/bn/bn_mont.c b/src/lib/libcrypto/bn/bn_mont.c index a54355ca37..559811b975 100644 --- a/src/lib/libcrypto/bn/bn_mont.c +++ b/src/lib/libcrypto/bn/bn_mont.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: bn_mont.c,v 1.44 2023/02/21 12:20:22 bcook Exp $ */ | 1 | /* $OpenBSD: bn_mont.c,v 1.45 2023/02/22 05:25:47 jsing Exp $ */ |
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 | * All rights reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
@@ -120,6 +120,7 @@ | |||
120 | #include <stdint.h> | 120 | #include <stdint.h> |
121 | #include <string.h> | 121 | #include <string.h> |
122 | 122 | ||
123 | #include "bn_internal.h" | ||
123 | #include "bn_local.h" | 124 | #include "bn_local.h" |
124 | 125 | ||
125 | BN_MONT_CTX * | 126 | BN_MONT_CTX * |
@@ -180,114 +181,89 @@ BN_MONT_CTX_copy(BN_MONT_CTX *dst, BN_MONT_CTX *src) | |||
180 | int | 181 | int |
181 | BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) | 182 | BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) |
182 | { | 183 | { |
184 | BIGNUM *N, *Ninv, *Rinv, *R; | ||
183 | int ret = 0; | 185 | int ret = 0; |
184 | BIGNUM *Ri, *R; | ||
185 | |||
186 | if (BN_is_zero(mod)) | ||
187 | return 0; | ||
188 | 186 | ||
189 | BN_CTX_start(ctx); | 187 | BN_CTX_start(ctx); |
190 | if ((Ri = BN_CTX_get(ctx)) == NULL) | 188 | |
189 | if ((N = BN_CTX_get(ctx)) == NULL) | ||
190 | goto err; | ||
191 | if ((Ninv = BN_CTX_get(ctx)) == NULL) | ||
192 | goto err; | ||
193 | if ((R = BN_CTX_get(ctx)) == NULL) | ||
194 | goto err; | ||
195 | if ((Rinv = BN_CTX_get(ctx)) == NULL) | ||
191 | goto err; | 196 | goto err; |
192 | R = &(mont->RR); /* grab RR as a temp */ | ||
193 | if (!BN_copy(&(mont->N), mod)) | ||
194 | goto err; /* Set N */ | ||
195 | mont->N.neg = 0; | ||
196 | 197 | ||
197 | { | 198 | /* Save modulus and determine length of R. */ |
198 | BIGNUM tmod; | 199 | if (BN_is_zero(mod)) |
199 | BN_ULONG buf[2]; | 200 | goto err; |
201 | if (!BN_copy(&mont->N, mod)) | ||
202 | goto err; | ||
203 | mont->N.neg = 0; | ||
204 | mont->ri = (BN_num_bits(mod) + (BN_BITS2 - 1)) / BN_BITS2 * BN_BITS2; | ||
205 | if (mont->ri * 2 < mont->ri) | ||
206 | goto err; | ||
200 | 207 | ||
201 | BN_init(&tmod); | 208 | /* |
202 | tmod.d = buf; | 209 | * Compute Ninv = (R * Rinv - 1)/N mod R, for R = 2^64. This provides |
203 | tmod.dmax = 2; | 210 | * a single or double word result (dependent on BN word size), that is |
204 | tmod.neg = 0; | 211 | * later used to implement Montgomery reduction. |
212 | */ | ||
213 | BN_zero(R); | ||
214 | if (!BN_set_bit(R, 64)) | ||
215 | goto err; | ||
205 | 216 | ||
206 | mont->ri = (BN_num_bits(mod) + | 217 | /* N = N mod R. */ |
207 | (BN_BITS2 - 1)) / BN_BITS2 * BN_BITS2; | 218 | if (!bn_wexpand(N, 2)) |
219 | goto err; | ||
220 | if (!BN_set_word(N, mod->d[0])) | ||
221 | goto err; | ||
222 | #if BN_BITS2 == 32 | ||
223 | if (mod->top > 1) { | ||
224 | N->d[1] = mod->d[1]; | ||
225 | N->top += bn_ct_ne_zero(N->d[1]); | ||
226 | } | ||
227 | #endif | ||
208 | 228 | ||
209 | #if defined(OPENSSL_BN_ASM_MONT) && (BN_BITS2<=32) | 229 | /* Rinv = R^-1 mod N */ |
210 | /* Only certain BN_BITS2<=32 platforms actually make use of | 230 | if ((BN_mod_inverse_ct(Rinv, R, N, ctx)) == NULL) |
211 | * n0[1], and we could use the #else case (with a shorter R | 231 | goto err; |
212 | * value) for the others. However, currently only the assembler | ||
213 | * files do know which is which. */ | ||
214 | 232 | ||
215 | BN_zero(R); | 233 | /* Ninv = (R * Rinv - 1) / N */ |
216 | if (!(BN_set_bit(R, 2 * BN_BITS2))) | 234 | if (!BN_lshift(Ninv, Rinv, 64)) |
235 | goto err; | ||
236 | if (BN_is_zero(Ninv)) { | ||
237 | /* R * Rinv == 0, set to R so that R * Rinv - 1 is mod R. */ | ||
238 | if (!BN_set_bit(Ninv, 64)) | ||
217 | goto err; | 239 | goto err; |
240 | } | ||
241 | if (!BN_sub_word(Ninv, 1)) | ||
242 | goto err; | ||
243 | if (!BN_div_ct(Ninv, NULL, Ninv, N, ctx)) | ||
244 | goto err; | ||
218 | 245 | ||
219 | tmod.top = 0; | 246 | /* Store least significant word(s) of Ninv. */ |
220 | if ((buf[0] = mod->d[0])) | 247 | mont->n0[0] = mont->n0[1] = 0; |
221 | tmod.top = 1; | 248 | if (Ninv->top > 0) |
222 | if ((buf[1] = mod->top > 1 ? mod->d[1] : 0)) | 249 | mont->n0[0] = Ninv->d[0]; |
223 | tmod.top = 2; | 250 | #if BN_BITS2 == 32 |
224 | 251 | /* Some BN_BITS2 == 32 platforms (namely parisc) use two words of Ninv. */ | |
225 | if ((BN_mod_inverse_ct(Ri, R, &tmod, ctx)) == NULL) | 252 | if (Ninv->top > 1) |
226 | goto err; | 253 | mont->n0[1] = Ninv->d[1]; |
227 | if (!BN_lshift(Ri, Ri, 2 * BN_BITS2)) | ||
228 | goto err; /* R*Ri */ | ||
229 | if (!BN_is_zero(Ri)) { | ||
230 | if (!BN_sub_word(Ri, 1)) | ||
231 | goto err; | ||
232 | } | ||
233 | else /* if N mod word size == 1 */ | ||
234 | { | ||
235 | if (!bn_wexpand(Ri, 2)) | ||
236 | goto err; | ||
237 | /* Ri-- (mod double word size) */ | ||
238 | Ri->neg = 0; | ||
239 | Ri->d[0] = BN_MASK2; | ||
240 | Ri->d[1] = BN_MASK2; | ||
241 | Ri->top = 2; | ||
242 | } | ||
243 | if (!BN_div_ct(Ri, NULL, Ri, &tmod, ctx)) | ||
244 | goto err; | ||
245 | /* Ni = (R*Ri-1)/N, | ||
246 | * keep only couple of least significant words: */ | ||
247 | mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0; | ||
248 | mont->n0[1] = (Ri->top > 1) ? Ri->d[1] : 0; | ||
249 | #else | ||
250 | BN_zero(R); | ||
251 | if (!(BN_set_bit(R, BN_BITS2))) | ||
252 | goto err; /* R */ | ||
253 | |||
254 | buf[0] = mod->d[0]; /* tmod = N mod word size */ | ||
255 | buf[1] = 0; | ||
256 | tmod.top = buf[0] != 0 ? 1 : 0; | ||
257 | /* Ri = R^-1 mod N*/ | ||
258 | if ((BN_mod_inverse_ct(Ri, R, &tmod, ctx)) == NULL) | ||
259 | goto err; | ||
260 | if (!BN_lshift(Ri, Ri, BN_BITS2)) | ||
261 | goto err; /* R*Ri */ | ||
262 | if (!BN_is_zero(Ri)) { | ||
263 | if (!BN_sub_word(Ri, 1)) | ||
264 | goto err; | ||
265 | } | ||
266 | else /* if N mod word size == 1 */ | ||
267 | { | ||
268 | if (!BN_set_word(Ri, BN_MASK2)) | ||
269 | goto err; /* Ri-- (mod word size) */ | ||
270 | } | ||
271 | if (!BN_div_ct(Ri, NULL, Ri, &tmod, ctx)) | ||
272 | goto err; | ||
273 | /* Ni = (R*Ri-1)/N, | ||
274 | * keep only least significant word: */ | ||
275 | mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0; | ||
276 | mont->n0[1] = 0; | ||
277 | #endif | 254 | #endif |
278 | } | ||
279 | 255 | ||
280 | /* setup RR for conversions */ | 256 | /* Compute RR = R * R mod N, for use when converting to Montgomery form. */ |
281 | BN_zero(&(mont->RR)); | 257 | BN_zero(&mont->RR); |
282 | if (!BN_set_bit(&(mont->RR), mont->ri*2)) | 258 | if (!BN_set_bit(&mont->RR, mont->ri * 2)) |
283 | goto err; | 259 | goto err; |
284 | if (!BN_mod_ct(&(mont->RR), &(mont->RR), &(mont->N), ctx)) | 260 | if (!BN_mod_ct(&mont->RR, &mont->RR, &mont->N, ctx)) |
285 | goto err; | 261 | goto err; |
286 | 262 | ||
287 | ret = 1; | 263 | ret = 1; |
288 | 264 | err: | |
289 | err: | ||
290 | BN_CTX_end(ctx); | 265 | BN_CTX_end(ctx); |
266 | |||
291 | return ret; | 267 | return ret; |
292 | } | 268 | } |
293 | 269 | ||
@@ -427,6 +403,7 @@ err: | |||
427 | int | 403 | int |
428 | BN_to_montgomery(BIGNUM *r, const BIGNUM *a, BN_MONT_CTX *mont, BN_CTX *ctx) | 404 | BN_to_montgomery(BIGNUM *r, const BIGNUM *a, BN_MONT_CTX *mont, BN_CTX *ctx) |
429 | { | 405 | { |
406 | /* Compute r = a * R * R * R^-1 mod N = aR mod N */ | ||
430 | return BN_mod_mul_montgomery(r, a, &mont->RR, mont, ctx); | 407 | return BN_mod_mul_montgomery(r, a, &mont->RR, mont, ctx); |
431 | } | 408 | } |
432 | 409 | ||