155714Skris/* crypto/bn/bn_div.c */ 255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 355714Skris * All rights reserved. 455714Skris * 555714Skris * This package is an SSL implementation written 655714Skris * by Eric Young (eay@cryptsoft.com). 755714Skris * The implementation was written so as to conform with Netscapes SSL. 8280304Sjkim * 955714Skris * This library is free for commercial and non-commercial use as long as 1055714Skris * the following conditions are aheared to. The following conditions 1155714Skris * apply to all code found in this distribution, be it the RC4, RSA, 1255714Skris * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1355714Skris * included with this distribution is covered by the same copyright terms 1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15280304Sjkim * 1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in 1755714Skris * the code are not to be removed. 1855714Skris * If this package is used in a product, Eric Young should be given attribution 1955714Skris * as the author of the parts of the library used. 2055714Skris * This can be in the form of a textual message at program startup or 2155714Skris * in documentation (online or textual) provided with the package. 22280304Sjkim * 2355714Skris * Redistribution and use in source and binary forms, with or without 2455714Skris * modification, are permitted provided that the following conditions 2555714Skris * are met: 2655714Skris * 1. Redistributions of source code must retain the copyright 2755714Skris * notice, this list of conditions and the following disclaimer. 2855714Skris * 2. Redistributions in binary form must reproduce the above copyright 2955714Skris * notice, this list of conditions and the following disclaimer in the 3055714Skris * documentation and/or other materials provided with the distribution. 3155714Skris * 3. All advertising materials mentioning features or use of this software 3255714Skris * must display the following acknowledgement: 3355714Skris * "This product includes cryptographic software written by 3455714Skris * Eric Young (eay@cryptsoft.com)" 3555714Skris * The word 'cryptographic' can be left out if the rouines from the library 3655714Skris * being used are not cryptographic related :-). 37280304Sjkim * 4. If you include any Windows specific code (or a derivative thereof) from 3855714Skris * the apps directory (application code) you must include an acknowledgement: 3955714Skris * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40280304Sjkim * 4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4455714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5155714Skris * SUCH DAMAGE. 52280304Sjkim * 5355714Skris * The licence and distribution terms for any publically available version or 5455714Skris * derivative of this code cannot be changed. i.e. this code cannot simply be 5555714Skris * copied and put under another distribution licence 5655714Skris * [including the GNU Public Licence.] 5755714Skris */ 5855714Skris 5955714Skris#include <stdio.h> 6055714Skris#include <openssl/bn.h> 6155714Skris#include "cryptlib.h" 6255714Skris#include "bn_lcl.h" 6355714Skris 6455714Skris/* The old slow way */ 6555714Skris#if 0 6659191Skrisint BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, 67280304Sjkim BN_CTX *ctx) 68280304Sjkim{ 69280304Sjkim int i, nm, nd; 70280304Sjkim int ret = 0; 71280304Sjkim BIGNUM *D; 7255714Skris 73280304Sjkim bn_check_top(m); 74280304Sjkim bn_check_top(d); 75280304Sjkim if (BN_is_zero(d)) { 76280304Sjkim BNerr(BN_F_BN_DIV, BN_R_DIV_BY_ZERO); 77280304Sjkim return (0); 78280304Sjkim } 7955714Skris 80280304Sjkim if (BN_ucmp(m, d) < 0) { 81280304Sjkim if (rem != NULL) { 82280304Sjkim if (BN_copy(rem, m) == NULL) 83280304Sjkim return (0); 84280304Sjkim } 85280304Sjkim if (dv != NULL) 86280304Sjkim BN_zero(dv); 87280304Sjkim return (1); 88280304Sjkim } 8955714Skris 90280304Sjkim BN_CTX_start(ctx); 91280304Sjkim D = BN_CTX_get(ctx); 92280304Sjkim if (dv == NULL) 93280304Sjkim dv = BN_CTX_get(ctx); 94280304Sjkim if (rem == NULL) 95280304Sjkim rem = BN_CTX_get(ctx); 96280304Sjkim if (D == NULL || dv == NULL || rem == NULL) 97280304Sjkim goto end; 9855714Skris 99280304Sjkim nd = BN_num_bits(d); 100280304Sjkim nm = BN_num_bits(m); 101280304Sjkim if (BN_copy(D, d) == NULL) 102280304Sjkim goto end; 103280304Sjkim if (BN_copy(rem, m) == NULL) 104280304Sjkim goto end; 10555714Skris 106280304Sjkim /* 107280304Sjkim * The next 2 are needed so we can do a dv->d[0]|=1 later since 108280304Sjkim * BN_lshift1 will only work once there is a value :-) 109280304Sjkim */ 110280304Sjkim BN_zero(dv); 111280304Sjkim if (bn_wexpand(dv, 1) == NULL) 112280304Sjkim goto end; 113280304Sjkim dv->top = 1; 11455714Skris 115280304Sjkim if (!BN_lshift(D, D, nm - nd)) 116280304Sjkim goto end; 117280304Sjkim for (i = nm - nd; i >= 0; i--) { 118280304Sjkim if (!BN_lshift1(dv, dv)) 119280304Sjkim goto end; 120280304Sjkim if (BN_ucmp(rem, D) >= 0) { 121280304Sjkim dv->d[0] |= 1; 122280304Sjkim if (!BN_usub(rem, rem, D)) 123280304Sjkim goto end; 124280304Sjkim } 12555714Skris/* CAN IMPROVE (and have now :=) */ 126280304Sjkim if (!BN_rshift1(D, D)) 127280304Sjkim goto end; 128280304Sjkim } 129280304Sjkim rem->neg = BN_is_zero(rem) ? 0 : m->neg; 130280304Sjkim dv->neg = m->neg ^ d->neg; 131280304Sjkim ret = 1; 13259191Skris end: 133280304Sjkim BN_CTX_end(ctx); 134280304Sjkim return (ret); 135280304Sjkim} 13655714Skris 13755714Skris#else 13855714Skris 139280304Sjkim# if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) \ 140109998Smarkm && !defined(PEDANTIC) && !defined(BN_DIV3W) 141280304Sjkim# if defined(__GNUC__) && __GNUC__>=2 142280304Sjkim# if defined(__i386) || defined (__i386__) 143280304Sjkim /*- 14459191Skris * There were two reasons for implementing this template: 14559191Skris * - GNU C generates a call to a function (__udivdi3 to be exact) 14659191Skris * in reply to ((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0 (I fail to 14759191Skris * understand why...); 14859191Skris * - divl doesn't only calculate quotient, but also leaves 14959191Skris * remainder in %edx which we can definitely use here:-) 15059191Skris * 151280304Sjkim * <appro@fy.chalmers.se> 15259191Skris */ 153280304Sjkim# undef bn_div_words 154280304Sjkim# define bn_div_words(n0,n1,d0) \ 155280304Sjkim ({ asm volatile ( \ 156280304Sjkim "divl %4" \ 157280304Sjkim : "=a"(q), "=d"(rem) \ 158280304Sjkim : "a"(n1), "d"(n0), "g"(d0) \ 159280304Sjkim : "cc"); \ 160280304Sjkim q; \ 161280304Sjkim }) 162280304Sjkim# define REMAINDER_IS_ALREADY_CALCULATED 163280304Sjkim# elif defined(__x86_64) && defined(SIXTY_FOUR_BIT_LONG) 164109998Smarkm /* 165109998Smarkm * Same story here, but it's 128-bit by 64-bit division. Wow! 166280304Sjkim * <appro@fy.chalmers.se> 167109998Smarkm */ 168280304Sjkim# undef bn_div_words 169280304Sjkim# define bn_div_words(n0,n1,d0) \ 170280304Sjkim ({ asm volatile ( \ 171280304Sjkim "divq %4" \ 172280304Sjkim : "=a"(q), "=d"(rem) \ 173280304Sjkim : "a"(n1), "d"(n0), "g"(d0) \ 174280304Sjkim : "cc"); \ 175280304Sjkim q; \ 176280304Sjkim }) 177280304Sjkim# define REMAINDER_IS_ALREADY_CALCULATED 178280304Sjkim# endif /* __<cpu> */ 179280304Sjkim# endif /* __GNUC__ */ 180280304Sjkim# endif /* OPENSSL_NO_ASM */ 18159191Skris 182280304Sjkim/*- 183280304Sjkim * BN_div computes dv := num / divisor, rounding towards 184194206Ssimon * zero, and sets up rm such that dv*divisor + rm = num holds. 185109998Smarkm * Thus: 186109998Smarkm * dv->neg == num->neg ^ divisor->neg (unless the result is zero) 187109998Smarkm * rm->neg == num->neg (unless the remainder is zero) 188109998Smarkm * If 'dv' or 'rm' is NULL, the respective value is not returned. 189109998Smarkm */ 19055714Skrisint BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, 191280304Sjkim BN_CTX *ctx) 192280304Sjkim{ 193280304Sjkim int norm_shift, i, loop; 194280304Sjkim BIGNUM *tmp, wnum, *snum, *sdiv, *res; 195280304Sjkim BN_ULONG *resp, *wnump; 196280304Sjkim BN_ULONG d0, d1; 197280304Sjkim int num_n, div_n; 198280304Sjkim int no_branch = 0; 19955714Skris 200280304Sjkim /* 201280304Sjkim * Invalid zero-padding would have particularly bad consequences so don't 202280304Sjkim * just rely on bn_check_top() here (bn_check_top() works only for 203280304Sjkim * BN_DEBUG builds) 204280304Sjkim */ 205280304Sjkim if ((num->top > 0 && num->d[num->top - 1] == 0) || 206280304Sjkim (divisor->top > 0 && divisor->d[divisor->top - 1] == 0)) { 207280304Sjkim BNerr(BN_F_BN_DIV, BN_R_NOT_INITIALIZED); 208280304Sjkim return 0; 209280304Sjkim } 210194206Ssimon 211280304Sjkim bn_check_top(num); 212280304Sjkim bn_check_top(divisor); 213194206Ssimon 214280304Sjkim if ((BN_get_flags(num, BN_FLG_CONSTTIME) != 0) 215280304Sjkim || (BN_get_flags(divisor, BN_FLG_CONSTTIME) != 0)) { 216280304Sjkim no_branch = 1; 217280304Sjkim } 218194206Ssimon 219280304Sjkim bn_check_top(dv); 220280304Sjkim bn_check_top(rm); 221280304Sjkim /*- bn_check_top(num); *//* 222280304Sjkim * 'num' has been checked already 223280304Sjkim */ 224280304Sjkim /*- bn_check_top(divisor); *//* 225280304Sjkim * 'divisor' has been checked already 226280304Sjkim */ 22755714Skris 228280304Sjkim if (BN_is_zero(divisor)) { 229280304Sjkim BNerr(BN_F_BN_DIV, BN_R_DIV_BY_ZERO); 230280304Sjkim return (0); 231280304Sjkim } 23255714Skris 233280304Sjkim if (!no_branch && BN_ucmp(num, divisor) < 0) { 234280304Sjkim if (rm != NULL) { 235280304Sjkim if (BN_copy(rm, num) == NULL) 236280304Sjkim return (0); 237280304Sjkim } 238280304Sjkim if (dv != NULL) 239280304Sjkim BN_zero(dv); 240280304Sjkim return (1); 241280304Sjkim } 24255714Skris 243280304Sjkim BN_CTX_start(ctx); 244280304Sjkim tmp = BN_CTX_get(ctx); 245280304Sjkim snum = BN_CTX_get(ctx); 246280304Sjkim sdiv = BN_CTX_get(ctx); 247280304Sjkim if (dv == NULL) 248280304Sjkim res = BN_CTX_get(ctx); 249280304Sjkim else 250280304Sjkim res = dv; 251280304Sjkim if (sdiv == NULL || res == NULL || tmp == NULL || snum == NULL) 252280304Sjkim goto err; 25355714Skris 254280304Sjkim /* First we normalise the numbers */ 255280304Sjkim norm_shift = BN_BITS2 - ((BN_num_bits(divisor)) % BN_BITS2); 256280304Sjkim if (!(BN_lshift(sdiv, divisor, norm_shift))) 257280304Sjkim goto err; 258280304Sjkim sdiv->neg = 0; 259280304Sjkim norm_shift += BN_BITS2; 260280304Sjkim if (!(BN_lshift(snum, num, norm_shift))) 261280304Sjkim goto err; 262280304Sjkim snum->neg = 0; 26355714Skris 264280304Sjkim if (no_branch) { 265280304Sjkim /* 266280304Sjkim * Since we don't know whether snum is larger than sdiv, we pad snum 267280304Sjkim * with enough zeroes without changing its value. 268280304Sjkim */ 269280304Sjkim if (snum->top <= sdiv->top + 1) { 270280304Sjkim if (bn_wexpand(snum, sdiv->top + 2) == NULL) 271280304Sjkim goto err; 272280304Sjkim for (i = snum->top; i < sdiv->top + 2; i++) 273280304Sjkim snum->d[i] = 0; 274280304Sjkim snum->top = sdiv->top + 2; 275280304Sjkim } else { 276280304Sjkim if (bn_wexpand(snum, snum->top + 1) == NULL) 277280304Sjkim goto err; 278280304Sjkim snum->d[snum->top] = 0; 279280304Sjkim snum->top++; 280280304Sjkim } 281280304Sjkim } 28255714Skris 283280304Sjkim div_n = sdiv->top; 284280304Sjkim num_n = snum->top; 285280304Sjkim loop = num_n - div_n; 286280304Sjkim /* 287280304Sjkim * Lets setup a 'window' into snum This is the part that corresponds to 288280304Sjkim * the current 'area' being divided 289280304Sjkim */ 290280304Sjkim wnum.neg = 0; 291280304Sjkim wnum.d = &(snum->d[loop]); 292280304Sjkim wnum.top = div_n; 293280304Sjkim /* 294280304Sjkim * only needed when BN_ucmp messes up the values between top and max 295280304Sjkim */ 296280304Sjkim wnum.dmax = snum->dmax - loop; /* so we don't step out of bounds */ 297194206Ssimon 298280304Sjkim /* Get the top 2 words of sdiv */ 299280304Sjkim /* div_n=sdiv->top; */ 300280304Sjkim d0 = sdiv->d[div_n - 1]; 301280304Sjkim d1 = (div_n == 1) ? 0 : sdiv->d[div_n - 2]; 302194206Ssimon 303280304Sjkim /* pointer to the 'top' of snum */ 304280304Sjkim wnump = &(snum->d[num_n - 1]); 305194206Ssimon 306280304Sjkim /* Setup to 'res' */ 307280304Sjkim res->neg = (num->neg ^ divisor->neg); 308280304Sjkim if (!bn_wexpand(res, (loop + 1))) 309280304Sjkim goto err; 310280304Sjkim res->top = loop - no_branch; 311280304Sjkim resp = &(res->d[loop - 1]); 312194206Ssimon 313280304Sjkim /* space for temp */ 314280304Sjkim if (!bn_wexpand(tmp, (div_n + 1))) 315280304Sjkim goto err; 316194206Ssimon 317280304Sjkim if (!no_branch) { 318280304Sjkim if (BN_ucmp(&wnum, sdiv) >= 0) { 319280304Sjkim /* 320280304Sjkim * If BN_DEBUG_RAND is defined BN_ucmp changes (via bn_pollute) 321280304Sjkim * the const bignum arguments => clean the values between top and 322280304Sjkim * max again 323280304Sjkim */ 324280304Sjkim bn_clear_top2max(&wnum); 325280304Sjkim bn_sub_words(wnum.d, wnum.d, sdiv->d, div_n); 326280304Sjkim *resp = 1; 327280304Sjkim } else 328280304Sjkim res->top--; 329280304Sjkim } 330238405Sjkim 331280304Sjkim /* 332280304Sjkim * if res->top == 0 then clear the neg value otherwise decrease the resp 333280304Sjkim * pointer 334280304Sjkim */ 335280304Sjkim if (res->top == 0) 336280304Sjkim res->neg = 0; 337280304Sjkim else 338280304Sjkim resp--; 339194206Ssimon 340280304Sjkim for (i = 0; i < loop - 1; i++, wnump--, resp--) { 341280304Sjkim BN_ULONG q, l0; 342280304Sjkim /* 343280304Sjkim * the first part of the loop uses the top two words of snum and sdiv 344280304Sjkim * to calculate a BN_ULONG q such that | wnum - sdiv * q | < sdiv 345280304Sjkim */ 346280304Sjkim# if defined(BN_DIV3W) && !defined(OPENSSL_NO_ASM) 347280304Sjkim BN_ULONG bn_div_3_words(BN_ULONG *, BN_ULONG, BN_ULONG); 348280304Sjkim q = bn_div_3_words(wnump, d1, d0); 349280304Sjkim# else 350280304Sjkim BN_ULONG n0, n1, rem = 0; 351194206Ssimon 352280304Sjkim n0 = wnump[0]; 353280304Sjkim n1 = wnump[-1]; 354280304Sjkim if (n0 == d0) 355280304Sjkim q = BN_MASK2; 356280304Sjkim else { /* n0 < d0 */ 357194206Ssimon 358280304Sjkim# ifdef BN_LLONG 359280304Sjkim BN_ULLONG t2; 360194206Ssimon 361280304Sjkim# if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words) 362280304Sjkim q = (BN_ULONG)(((((BN_ULLONG) n0) << BN_BITS2) | n1) / d0); 363280304Sjkim# else 364280304Sjkim q = bn_div_words(n0, n1, d0); 365280304Sjkim# ifdef BN_DEBUG_LEVITTE 366280304Sjkim fprintf(stderr, "DEBUG: bn_div_words(0x%08X,0x%08X,0x%08\ 367280304SjkimX) -> 0x%08X\n", n0, n1, d0, q); 368280304Sjkim# endif 369280304Sjkim# endif 370194206Ssimon 371280304Sjkim# ifndef REMAINDER_IS_ALREADY_CALCULATED 372280304Sjkim /* 373280304Sjkim * rem doesn't have to be BN_ULLONG. The least we 374280304Sjkim * know it's less that d0, isn't it? 375280304Sjkim */ 376280304Sjkim rem = (n1 - q * d0) & BN_MASK2; 377280304Sjkim# endif 378280304Sjkim t2 = (BN_ULLONG) d1 *q; 379194206Ssimon 380280304Sjkim for (;;) { 381280304Sjkim if (t2 <= ((((BN_ULLONG) rem) << BN_BITS2) | wnump[-2])) 382280304Sjkim break; 383280304Sjkim q--; 384280304Sjkim rem += d0; 385280304Sjkim if (rem < d0) 386280304Sjkim break; /* don't let rem overflow */ 387280304Sjkim t2 -= d1; 388280304Sjkim } 389280304Sjkim# else /* !BN_LLONG */ 390280304Sjkim BN_ULONG t2l, t2h; 391194206Ssimon 392280304Sjkim q = bn_div_words(n0, n1, d0); 393280304Sjkim# ifdef BN_DEBUG_LEVITTE 394280304Sjkim fprintf(stderr, "DEBUG: bn_div_words(0x%08X,0x%08X,0x%08\ 395280304SjkimX) -> 0x%08X\n", n0, n1, d0, q); 396280304Sjkim# endif 397280304Sjkim# ifndef REMAINDER_IS_ALREADY_CALCULATED 398280304Sjkim rem = (n1 - q * d0) & BN_MASK2; 399280304Sjkim# endif 400194206Ssimon 401280304Sjkim# if defined(BN_UMULT_LOHI) 402280304Sjkim BN_UMULT_LOHI(t2l, t2h, d1, q); 403280304Sjkim# elif defined(BN_UMULT_HIGH) 404280304Sjkim t2l = d1 * q; 405280304Sjkim t2h = BN_UMULT_HIGH(d1, q); 406280304Sjkim# else 407280304Sjkim { 408280304Sjkim BN_ULONG ql, qh; 409280304Sjkim t2l = LBITS(d1); 410280304Sjkim t2h = HBITS(d1); 411280304Sjkim ql = LBITS(q); 412280304Sjkim qh = HBITS(q); 413280304Sjkim mul64(t2l, t2h, ql, qh); /* t2=(BN_ULLONG)d1*q; */ 414280304Sjkim } 415280304Sjkim# endif 416194206Ssimon 417280304Sjkim for (;;) { 418280304Sjkim if ((t2h < rem) || ((t2h == rem) && (t2l <= wnump[-2]))) 419280304Sjkim break; 420280304Sjkim q--; 421280304Sjkim rem += d0; 422280304Sjkim if (rem < d0) 423280304Sjkim break; /* don't let rem overflow */ 424280304Sjkim if (t2l < d1) 425280304Sjkim t2h--; 426280304Sjkim t2l -= d1; 427280304Sjkim } 428280304Sjkim# endif /* !BN_LLONG */ 429280304Sjkim } 430280304Sjkim# endif /* !BN_DIV3W */ 431280304Sjkim 432280304Sjkim l0 = bn_mul_words(tmp->d, sdiv->d, div_n, q); 433280304Sjkim tmp->d[div_n] = l0; 434280304Sjkim wnum.d--; 435280304Sjkim /* 436280304Sjkim * ingore top values of the bignums just sub the two BN_ULONG arrays 437280304Sjkim * with bn_sub_words 438280304Sjkim */ 439280304Sjkim if (bn_sub_words(wnum.d, wnum.d, tmp->d, div_n + 1)) { 440280304Sjkim /* 441280304Sjkim * Note: As we have considered only the leading two BN_ULONGs in 442280304Sjkim * the calculation of q, sdiv * q might be greater than wnum (but 443280304Sjkim * then (q-1) * sdiv is less or equal than wnum) 444280304Sjkim */ 445280304Sjkim q--; 446280304Sjkim if (bn_add_words(wnum.d, wnum.d, sdiv->d, div_n)) 447280304Sjkim /* 448280304Sjkim * we can't have an overflow here (assuming that q != 0, but 449280304Sjkim * if q == 0 then tmp is zero anyway) 450280304Sjkim */ 451280304Sjkim (*wnump)++; 452280304Sjkim } 453280304Sjkim /* store part of the result */ 454280304Sjkim *resp = q; 455280304Sjkim } 456280304Sjkim bn_correct_top(snum); 457280304Sjkim if (rm != NULL) { 458280304Sjkim /* 459280304Sjkim * Keep a copy of the neg flag in num because if rm==num BN_rshift() 460280304Sjkim * will overwrite it. 461280304Sjkim */ 462280304Sjkim int neg = num->neg; 463280304Sjkim BN_rshift(rm, snum, norm_shift); 464280304Sjkim if (!BN_is_zero(rm)) 465280304Sjkim rm->neg = neg; 466280304Sjkim bn_check_top(rm); 467280304Sjkim } 468280304Sjkim if (no_branch) 469280304Sjkim bn_correct_top(res); 470280304Sjkim BN_CTX_end(ctx); 471280304Sjkim return (1); 472280304Sjkim err: 473280304Sjkim bn_check_top(rm); 474280304Sjkim BN_CTX_end(ctx); 475280304Sjkim return (0); 476280304Sjkim} 477194206Ssimon#endif 478