1*b4a69cdbStb /* $OpenBSD: bn_recp.c,v 1.30 2025/01/22 12:53:16 tb Exp $ */
25b37fcf3Sryker /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
35b37fcf3Sryker * All rights reserved.
45b37fcf3Sryker *
55b37fcf3Sryker * This package is an SSL implementation written
65b37fcf3Sryker * by Eric Young (eay@cryptsoft.com).
75b37fcf3Sryker * The implementation was written so as to conform with Netscapes SSL.
85b37fcf3Sryker *
95b37fcf3Sryker * This library is free for commercial and non-commercial use as long as
105b37fcf3Sryker * the following conditions are aheared to. The following conditions
115b37fcf3Sryker * apply to all code found in this distribution, be it the RC4, RSA,
125b37fcf3Sryker * lhash, DES, etc., code; not just the SSL code. The SSL documentation
135b37fcf3Sryker * included with this distribution is covered by the same copyright terms
145b37fcf3Sryker * except that the holder is Tim Hudson (tjh@cryptsoft.com).
155b37fcf3Sryker *
165b37fcf3Sryker * Copyright remains Eric Young's, and as such any Copyright notices in
175b37fcf3Sryker * the code are not to be removed.
185b37fcf3Sryker * If this package is used in a product, Eric Young should be given attribution
195b37fcf3Sryker * as the author of the parts of the library used.
205b37fcf3Sryker * This can be in the form of a textual message at program startup or
215b37fcf3Sryker * in documentation (online or textual) provided with the package.
225b37fcf3Sryker *
235b37fcf3Sryker * Redistribution and use in source and binary forms, with or without
245b37fcf3Sryker * modification, are permitted provided that the following conditions
255b37fcf3Sryker * are met:
265b37fcf3Sryker * 1. Redistributions of source code must retain the copyright
275b37fcf3Sryker * notice, this list of conditions and the following disclaimer.
285b37fcf3Sryker * 2. Redistributions in binary form must reproduce the above copyright
295b37fcf3Sryker * notice, this list of conditions and the following disclaimer in the
305b37fcf3Sryker * documentation and/or other materials provided with the distribution.
315b37fcf3Sryker * 3. All advertising materials mentioning features or use of this software
325b37fcf3Sryker * must display the following acknowledgement:
335b37fcf3Sryker * "This product includes cryptographic software written by
345b37fcf3Sryker * Eric Young (eay@cryptsoft.com)"
355b37fcf3Sryker * The word 'cryptographic' can be left out if the rouines from the library
365b37fcf3Sryker * being used are not cryptographic related :-).
375b37fcf3Sryker * 4. If you include any Windows specific code (or a derivative thereof) from
385b37fcf3Sryker * the apps directory (application code) you must include an acknowledgement:
395b37fcf3Sryker * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
405b37fcf3Sryker *
415b37fcf3Sryker * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
425b37fcf3Sryker * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
435b37fcf3Sryker * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
445b37fcf3Sryker * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
455b37fcf3Sryker * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
465b37fcf3Sryker * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
475b37fcf3Sryker * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
485b37fcf3Sryker * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
495b37fcf3Sryker * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
505b37fcf3Sryker * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
515b37fcf3Sryker * SUCH DAMAGE.
525b37fcf3Sryker *
535b37fcf3Sryker * The licence and distribution terms for any publically available version or
545b37fcf3Sryker * derivative of this code cannot be changed. i.e. this code cannot simply be
555b37fcf3Sryker * copied and put under another distribution licence
565b37fcf3Sryker * [including the GNU Public Licence.]
575b37fcf3Sryker */
585b37fcf3Sryker
595b37fcf3Sryker #include <stdio.h>
60b6ab114eSjsing
61b6ab114eSjsing #include <openssl/err.h>
62b6ab114eSjsing
63c9675a23Stb #include "bn_local.h"
645b37fcf3Sryker
6505328004Stb struct bn_recp_ctx_st {
6605328004Stb BIGNUM *N; /* the divisor */
6705328004Stb BIGNUM *Nr; /* the reciprocal 2^shift / N */
6805328004Stb int num_bits; /* number of bits in N */
6905328004Stb int shift;
7005328004Stb } /* BN_RECP_CTX */;
715b37fcf3Sryker
722bd9bb84Sjsing BN_RECP_CTX *
BN_RECP_CTX_create(const BIGNUM * N)7305328004Stb BN_RECP_CTX_create(const BIGNUM *N)
74913ec974Sbeck {
7505328004Stb BN_RECP_CTX *recp;
765b37fcf3Sryker
7705328004Stb if ((recp = calloc(1, sizeof(*recp))) == NULL)
7805328004Stb goto err;
7905328004Stb
8005328004Stb if ((recp->N = BN_dup(N)) == NULL)
8105328004Stb goto err;
82*b4a69cdbStb BN_set_negative(recp->N, 0);
8305328004Stb recp->num_bits = BN_num_bits(recp->N);
8405328004Stb
8505328004Stb if ((recp->Nr = BN_new()) == NULL)
8605328004Stb goto err;
8705328004Stb
8805328004Stb return recp;
8905328004Stb
9005328004Stb err:
9105328004Stb BN_RECP_CTX_free(recp);
9205328004Stb
9359c697bfStb return NULL;
94913ec974Sbeck }
95913ec974Sbeck
962bd9bb84Sjsing void
BN_RECP_CTX_free(BN_RECP_CTX * recp)972bd9bb84Sjsing BN_RECP_CTX_free(BN_RECP_CTX *recp)
98913ec974Sbeck {
99913ec974Sbeck if (recp == NULL)
100913ec974Sbeck return;
101913ec974Sbeck
10205328004Stb BN_free(recp->N);
10305328004Stb BN_free(recp->Nr);
10405328004Stb freezero(recp, sizeof(*recp));
105913ec974Sbeck }
106913ec974Sbeck
107abfe84ecStb /* len is the expected size of the result
108abfe84ecStb * We actually calculate with an extra word of precision, so
109abfe84ecStb * we can do faster division if the remainder is not required.
110abfe84ecStb */
111abfe84ecStb /* r := 2^len / m */
112abfe84ecStb static int
BN_reciprocal(BIGNUM * r,const BIGNUM * m,int len,BN_CTX * ctx)113abfe84ecStb BN_reciprocal(BIGNUM *r, const BIGNUM *m, int len, BN_CTX *ctx)
114913ec974Sbeck {
115abfe84ecStb int ret = -1;
116abfe84ecStb BIGNUM *t;
117913ec974Sbeck
118ba5406e9Sbeck BN_CTX_start(ctx);
119abfe84ecStb if ((t = BN_CTX_get(ctx)) == NULL)
1202bd9bb84Sjsing goto err;
121913ec974Sbeck
122abfe84ecStb if (!BN_set_bit(t, len))
123abfe84ecStb goto err;
124abfe84ecStb
125abfe84ecStb if (!BN_div_ct(r, NULL, t, m, ctx))
126abfe84ecStb goto err;
127abfe84ecStb
128abfe84ecStb ret = len;
1292bd9bb84Sjsing
130913ec974Sbeck err:
131ba5406e9Sbeck BN_CTX_end(ctx);
13259c697bfStb return ret;
133913ec974Sbeck }
134913ec974Sbeck
1359d6e4a9aStb int
BN_div_reciprocal(BIGNUM * dv,BIGNUM * rem,const BIGNUM * m,BN_RECP_CTX * recp,BN_CTX * ctx)13647537ea9Stb BN_div_reciprocal(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, BN_RECP_CTX *recp,
1372bd9bb84Sjsing BN_CTX *ctx)
138913ec974Sbeck {
139ba5406e9Sbeck int i, j, ret = 0;
140913ec974Sbeck BIGNUM *a, *b, *d, *r;
141913ec974Sbeck
142ba5406e9Sbeck BN_CTX_start(ctx);
143ba5406e9Sbeck a = BN_CTX_get(ctx);
144ba5406e9Sbeck b = BN_CTX_get(ctx);
145913ec974Sbeck if (dv != NULL)
146913ec974Sbeck d = dv;
147913ec974Sbeck else
148ba5406e9Sbeck d = BN_CTX_get(ctx);
149913ec974Sbeck if (rem != NULL)
150913ec974Sbeck r = rem;
151913ec974Sbeck else
152ba5406e9Sbeck r = BN_CTX_get(ctx);
1532bd9bb84Sjsing if (a == NULL || b == NULL || d == NULL || r == NULL)
1542bd9bb84Sjsing goto err;
155913ec974Sbeck
15605328004Stb if (BN_ucmp(m, recp->N) < 0) {
1574fcf65c5Sdjm BN_zero(d);
158cef8f41dStb if (!bn_copy(r, m)) {
1594c1eb2ebSdoug BN_CTX_end(ctx);
1602bd9bb84Sjsing return 0;
1614c1eb2ebSdoug }
162ba5406e9Sbeck BN_CTX_end(ctx);
16359c697bfStb return 1;
164913ec974Sbeck }
165913ec974Sbeck
166913ec974Sbeck /* We want the remainder
167913ec974Sbeck * Given input of ABCDEF / ab
168913ec974Sbeck * we need multiply ABCDEF by 3 digests of the reciprocal of ab
169913ec974Sbeck *
170913ec974Sbeck */
171913ec974Sbeck
172da347917Sbeck /* i := max(BN_num_bits(m), 2*BN_num_bits(N)) */
173da347917Sbeck i = BN_num_bits(m);
174ba5406e9Sbeck j = recp->num_bits << 1;
1752bd9bb84Sjsing if (j > i)
1762bd9bb84Sjsing i = j;
177913ec974Sbeck
178da347917Sbeck /* Nr := round(2^i / N) */
179913ec974Sbeck if (i != recp->shift)
18005328004Stb recp->shift = BN_reciprocal(recp->Nr, recp->N, i, ctx);
181bb2f0c56Sdoug
182bb2f0c56Sdoug /* BN_reciprocal returns i, or -1 for an error */
1832bd9bb84Sjsing if (recp->shift == -1)
1842bd9bb84Sjsing goto err;
185913ec974Sbeck
186da347917Sbeck /* d := |round(round(m / 2^BN_num_bits(N)) * recp->Nr / 2^(i - BN_num_bits(N)))|
187da347917Sbeck * = |round(round(m / 2^BN_num_bits(N)) * round(2^i / N) / 2^(i - BN_num_bits(N)))|
188da347917Sbeck * <= |(m / 2^BN_num_bits(N)) * (2^i / N) * (2^BN_num_bits(N) / 2^i)|
189da347917Sbeck * = |m/N|
190da347917Sbeck */
1912bd9bb84Sjsing if (!BN_rshift(a, m, recp->num_bits))
1922bd9bb84Sjsing goto err;
19305328004Stb if (!BN_mul(b, a, recp->Nr, ctx))
1942bd9bb84Sjsing goto err;
1952bd9bb84Sjsing if (!BN_rshift(d, b, i - recp->num_bits))
1962bd9bb84Sjsing goto err;
197913ec974Sbeck d->neg = 0;
198da347917Sbeck
19905328004Stb if (!BN_mul(b, recp->N, d, ctx))
2002bd9bb84Sjsing goto err;
2012bd9bb84Sjsing if (!BN_usub(r, m, b))
2022bd9bb84Sjsing goto err;
203913ec974Sbeck r->neg = 0;
204913ec974Sbeck
205913ec974Sbeck #if 1
206ba5406e9Sbeck j = 0;
20705328004Stb while (BN_ucmp(r, recp->N) >= 0) {
2082bd9bb84Sjsing if (j++ > 2) {
2095067ae9fSbeck BNerror(BN_R_BAD_RECIPROCAL);
2105b37fcf3Sryker goto err;
2115b37fcf3Sryker }
21205328004Stb if (!BN_usub(r, r, recp->N))
2132bd9bb84Sjsing goto err;
2142bd9bb84Sjsing if (!BN_add_word(d, 1))
2152bd9bb84Sjsing goto err;
2165b37fcf3Sryker }
217913ec974Sbeck #endif
2185b37fcf3Sryker
219896da13fSjsing BN_set_negative(r, m->neg);
22005328004Stb BN_set_negative(d, m->neg ^ recp->N->neg);
221896da13fSjsing
2225b37fcf3Sryker ret = 1;
2232bd9bb84Sjsing
2245b37fcf3Sryker err:
225ba5406e9Sbeck BN_CTX_end(ctx);
22659c697bfStb return ret;
2275b37fcf3Sryker }
2285b37fcf3Sryker
229e9711763Stb /* Compute r = (x * y) % m. */
2302bd9bb84Sjsing int
BN_mod_mul_reciprocal(BIGNUM * r,const BIGNUM * x,const BIGNUM * y,BN_RECP_CTX * recp,BN_CTX * ctx)231abfe84ecStb BN_mod_mul_reciprocal(BIGNUM *r, const BIGNUM *x, const BIGNUM *y,
232abfe84ecStb BN_RECP_CTX *recp, BN_CTX *ctx)
2335b37fcf3Sryker {
23402fba168Stb if (!BN_mul(r, x, y, ctx))
23502fba168Stb return 0;
2365b37fcf3Sryker
23747537ea9Stb return BN_div_reciprocal(NULL, r, r, recp, ctx);
238abfe84ecStb }
239da347917Sbeck
24002fba168Stb /* Compute r = x^2 % m. */
24102fba168Stb int
BN_mod_sqr_reciprocal(BIGNUM * r,const BIGNUM * x,BN_RECP_CTX * recp,BN_CTX * ctx)24202fba168Stb BN_mod_sqr_reciprocal(BIGNUM *r, const BIGNUM *x, BN_RECP_CTX *recp, BN_CTX *ctx)
24302fba168Stb {
24402fba168Stb if (!BN_sqr(r, x, ctx))
24502fba168Stb return 0;
2462bd9bb84Sjsing
24747537ea9Stb return BN_div_reciprocal(NULL, r, r, recp, ctx);
2485b37fcf3Sryker }
249