1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci#include "internal/cryptlib.h"
11e1051a39Sopenharmony_ci#include "bn_local.h"
12e1051a39Sopenharmony_ci
13e1051a39Sopenharmony_civoid BN_RECP_CTX_init(BN_RECP_CTX *recp)
14e1051a39Sopenharmony_ci{
15e1051a39Sopenharmony_ci    memset(recp, 0, sizeof(*recp));
16e1051a39Sopenharmony_ci    bn_init(&(recp->N));
17e1051a39Sopenharmony_ci    bn_init(&(recp->Nr));
18e1051a39Sopenharmony_ci}
19e1051a39Sopenharmony_ci
20e1051a39Sopenharmony_ciBN_RECP_CTX *BN_RECP_CTX_new(void)
21e1051a39Sopenharmony_ci{
22e1051a39Sopenharmony_ci    BN_RECP_CTX *ret;
23e1051a39Sopenharmony_ci
24e1051a39Sopenharmony_ci    if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) {
25e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_BN, ERR_R_MALLOC_FAILURE);
26e1051a39Sopenharmony_ci        return NULL;
27e1051a39Sopenharmony_ci    }
28e1051a39Sopenharmony_ci
29e1051a39Sopenharmony_ci    bn_init(&(ret->N));
30e1051a39Sopenharmony_ci    bn_init(&(ret->Nr));
31e1051a39Sopenharmony_ci    ret->flags = BN_FLG_MALLOCED;
32e1051a39Sopenharmony_ci    return ret;
33e1051a39Sopenharmony_ci}
34e1051a39Sopenharmony_ci
35e1051a39Sopenharmony_civoid BN_RECP_CTX_free(BN_RECP_CTX *recp)
36e1051a39Sopenharmony_ci{
37e1051a39Sopenharmony_ci    if (recp == NULL)
38e1051a39Sopenharmony_ci        return;
39e1051a39Sopenharmony_ci    BN_free(&recp->N);
40e1051a39Sopenharmony_ci    BN_free(&recp->Nr);
41e1051a39Sopenharmony_ci    if (recp->flags & BN_FLG_MALLOCED)
42e1051a39Sopenharmony_ci        OPENSSL_free(recp);
43e1051a39Sopenharmony_ci}
44e1051a39Sopenharmony_ci
45e1051a39Sopenharmony_ciint BN_RECP_CTX_set(BN_RECP_CTX *recp, const BIGNUM *d, BN_CTX *ctx)
46e1051a39Sopenharmony_ci{
47e1051a39Sopenharmony_ci    if (!BN_copy(&(recp->N), d))
48e1051a39Sopenharmony_ci        return 0;
49e1051a39Sopenharmony_ci    BN_zero(&(recp->Nr));
50e1051a39Sopenharmony_ci    recp->num_bits = BN_num_bits(d);
51e1051a39Sopenharmony_ci    recp->shift = 0;
52e1051a39Sopenharmony_ci    return 1;
53e1051a39Sopenharmony_ci}
54e1051a39Sopenharmony_ci
55e1051a39Sopenharmony_ciint BN_mod_mul_reciprocal(BIGNUM *r, const BIGNUM *x, const BIGNUM *y,
56e1051a39Sopenharmony_ci                          BN_RECP_CTX *recp, BN_CTX *ctx)
57e1051a39Sopenharmony_ci{
58e1051a39Sopenharmony_ci    int ret = 0;
59e1051a39Sopenharmony_ci    BIGNUM *a;
60e1051a39Sopenharmony_ci    const BIGNUM *ca;
61e1051a39Sopenharmony_ci
62e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
63e1051a39Sopenharmony_ci    if ((a = BN_CTX_get(ctx)) == NULL)
64e1051a39Sopenharmony_ci        goto err;
65e1051a39Sopenharmony_ci    if (y != NULL) {
66e1051a39Sopenharmony_ci        if (x == y) {
67e1051a39Sopenharmony_ci            if (!BN_sqr(a, x, ctx))
68e1051a39Sopenharmony_ci                goto err;
69e1051a39Sopenharmony_ci        } else {
70e1051a39Sopenharmony_ci            if (!BN_mul(a, x, y, ctx))
71e1051a39Sopenharmony_ci                goto err;
72e1051a39Sopenharmony_ci        }
73e1051a39Sopenharmony_ci        ca = a;
74e1051a39Sopenharmony_ci    } else
75e1051a39Sopenharmony_ci        ca = x;                 /* Just do the mod */
76e1051a39Sopenharmony_ci
77e1051a39Sopenharmony_ci    ret = BN_div_recp(NULL, r, ca, recp, ctx);
78e1051a39Sopenharmony_ci err:
79e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
80e1051a39Sopenharmony_ci    bn_check_top(r);
81e1051a39Sopenharmony_ci    return ret;
82e1051a39Sopenharmony_ci}
83e1051a39Sopenharmony_ci
84e1051a39Sopenharmony_ciint BN_div_recp(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m,
85e1051a39Sopenharmony_ci                BN_RECP_CTX *recp, BN_CTX *ctx)
86e1051a39Sopenharmony_ci{
87e1051a39Sopenharmony_ci    int i, j, ret = 0;
88e1051a39Sopenharmony_ci    BIGNUM *a, *b, *d, *r;
89e1051a39Sopenharmony_ci
90e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
91e1051a39Sopenharmony_ci    d = (dv != NULL) ? dv : BN_CTX_get(ctx);
92e1051a39Sopenharmony_ci    r = (rem != NULL) ? rem : BN_CTX_get(ctx);
93e1051a39Sopenharmony_ci    a = BN_CTX_get(ctx);
94e1051a39Sopenharmony_ci    b = BN_CTX_get(ctx);
95e1051a39Sopenharmony_ci    if (b == NULL)
96e1051a39Sopenharmony_ci        goto err;
97e1051a39Sopenharmony_ci
98e1051a39Sopenharmony_ci    if (BN_ucmp(m, &(recp->N)) < 0) {
99e1051a39Sopenharmony_ci        BN_zero(d);
100e1051a39Sopenharmony_ci        if (!BN_copy(r, m)) {
101e1051a39Sopenharmony_ci            BN_CTX_end(ctx);
102e1051a39Sopenharmony_ci            return 0;
103e1051a39Sopenharmony_ci        }
104e1051a39Sopenharmony_ci        BN_CTX_end(ctx);
105e1051a39Sopenharmony_ci        return 1;
106e1051a39Sopenharmony_ci    }
107e1051a39Sopenharmony_ci
108e1051a39Sopenharmony_ci    /*
109e1051a39Sopenharmony_ci     * We want the remainder Given input of ABCDEF / ab we need multiply
110e1051a39Sopenharmony_ci     * ABCDEF by 3 digests of the reciprocal of ab
111e1051a39Sopenharmony_ci     */
112e1051a39Sopenharmony_ci
113e1051a39Sopenharmony_ci    /* i := max(BN_num_bits(m), 2*BN_num_bits(N)) */
114e1051a39Sopenharmony_ci    i = BN_num_bits(m);
115e1051a39Sopenharmony_ci    j = recp->num_bits << 1;
116e1051a39Sopenharmony_ci    if (j > i)
117e1051a39Sopenharmony_ci        i = j;
118e1051a39Sopenharmony_ci
119e1051a39Sopenharmony_ci    /* Nr := round(2^i / N) */
120e1051a39Sopenharmony_ci    if (i != recp->shift)
121e1051a39Sopenharmony_ci        recp->shift = BN_reciprocal(&(recp->Nr), &(recp->N), i, ctx);
122e1051a39Sopenharmony_ci    /* BN_reciprocal could have returned -1 for an error */
123e1051a39Sopenharmony_ci    if (recp->shift == -1)
124e1051a39Sopenharmony_ci        goto err;
125e1051a39Sopenharmony_ci
126e1051a39Sopenharmony_ci    /*-
127e1051a39Sopenharmony_ci     * d := |round(round(m / 2^BN_num_bits(N)) * recp->Nr / 2^(i - BN_num_bits(N)))|
128e1051a39Sopenharmony_ci     *    = |round(round(m / 2^BN_num_bits(N)) * round(2^i / N) / 2^(i - BN_num_bits(N)))|
129e1051a39Sopenharmony_ci     *   <= |(m / 2^BN_num_bits(N)) * (2^i / N) * (2^BN_num_bits(N) / 2^i)|
130e1051a39Sopenharmony_ci     *    = |m/N|
131e1051a39Sopenharmony_ci     */
132e1051a39Sopenharmony_ci    if (!BN_rshift(a, m, recp->num_bits))
133e1051a39Sopenharmony_ci        goto err;
134e1051a39Sopenharmony_ci    if (!BN_mul(b, a, &(recp->Nr), ctx))
135e1051a39Sopenharmony_ci        goto err;
136e1051a39Sopenharmony_ci    if (!BN_rshift(d, b, i - recp->num_bits))
137e1051a39Sopenharmony_ci        goto err;
138e1051a39Sopenharmony_ci    d->neg = 0;
139e1051a39Sopenharmony_ci
140e1051a39Sopenharmony_ci    if (!BN_mul(b, &(recp->N), d, ctx))
141e1051a39Sopenharmony_ci        goto err;
142e1051a39Sopenharmony_ci    if (!BN_usub(r, m, b))
143e1051a39Sopenharmony_ci        goto err;
144e1051a39Sopenharmony_ci    r->neg = 0;
145e1051a39Sopenharmony_ci
146e1051a39Sopenharmony_ci    j = 0;
147e1051a39Sopenharmony_ci    while (BN_ucmp(r, &(recp->N)) >= 0) {
148e1051a39Sopenharmony_ci        if (j++ > 2) {
149e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_BN, BN_R_BAD_RECIPROCAL);
150e1051a39Sopenharmony_ci            goto err;
151e1051a39Sopenharmony_ci        }
152e1051a39Sopenharmony_ci        if (!BN_usub(r, r, &(recp->N)))
153e1051a39Sopenharmony_ci            goto err;
154e1051a39Sopenharmony_ci        if (!BN_add_word(d, 1))
155e1051a39Sopenharmony_ci            goto err;
156e1051a39Sopenharmony_ci    }
157e1051a39Sopenharmony_ci
158e1051a39Sopenharmony_ci    r->neg = BN_is_zero(r) ? 0 : m->neg;
159e1051a39Sopenharmony_ci    d->neg = m->neg ^ recp->N.neg;
160e1051a39Sopenharmony_ci    ret = 1;
161e1051a39Sopenharmony_ci err:
162e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
163e1051a39Sopenharmony_ci    bn_check_top(dv);
164e1051a39Sopenharmony_ci    bn_check_top(rem);
165e1051a39Sopenharmony_ci    return ret;
166e1051a39Sopenharmony_ci}
167e1051a39Sopenharmony_ci
168e1051a39Sopenharmony_ci/*
169e1051a39Sopenharmony_ci * len is the expected size of the result We actually calculate with an extra
170e1051a39Sopenharmony_ci * word of precision, so we can do faster division if the remainder is not
171e1051a39Sopenharmony_ci * required.
172e1051a39Sopenharmony_ci */
173e1051a39Sopenharmony_ci/* r := 2^len / m */
174e1051a39Sopenharmony_ciint BN_reciprocal(BIGNUM *r, const BIGNUM *m, int len, BN_CTX *ctx)
175e1051a39Sopenharmony_ci{
176e1051a39Sopenharmony_ci    int ret = -1;
177e1051a39Sopenharmony_ci    BIGNUM *t;
178e1051a39Sopenharmony_ci
179e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
180e1051a39Sopenharmony_ci    if ((t = BN_CTX_get(ctx)) == NULL)
181e1051a39Sopenharmony_ci        goto err;
182e1051a39Sopenharmony_ci
183e1051a39Sopenharmony_ci    if (!BN_set_bit(t, len))
184e1051a39Sopenharmony_ci        goto err;
185e1051a39Sopenharmony_ci
186e1051a39Sopenharmony_ci    if (!BN_div(r, NULL, t, m, ctx))
187e1051a39Sopenharmony_ci        goto err;
188e1051a39Sopenharmony_ci
189e1051a39Sopenharmony_ci    ret = len;
190e1051a39Sopenharmony_ci err:
191e1051a39Sopenharmony_ci    bn_check_top(r);
192e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
193e1051a39Sopenharmony_ci    return ret;
194e1051a39Sopenharmony_ci}
195