1*f0865ec9SKyle Evans /*
2*f0865ec9SKyle Evans * Copyright (C) 2017 - This file is part of libecc project
3*f0865ec9SKyle Evans *
4*f0865ec9SKyle Evans * Authors:
5*f0865ec9SKyle Evans * Ryad BENADJILA <ryadbenadjila@gmail.com>
6*f0865ec9SKyle Evans * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7*f0865ec9SKyle Evans * Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr>
8*f0865ec9SKyle Evans *
9*f0865ec9SKyle Evans * Contributors:
10*f0865ec9SKyle Evans * Nicolas VIVET <nicolas.vivet@ssi.gouv.fr>
11*f0865ec9SKyle Evans * Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr>
12*f0865ec9SKyle Evans *
13*f0865ec9SKyle Evans * This software is licensed under a dual BSD and GPL v2 license.
14*f0865ec9SKyle Evans * See LICENSE file at the root folder of the project.
15*f0865ec9SKyle Evans */
16*f0865ec9SKyle Evans #include <libecc/nn/nn_modinv.h>
17*f0865ec9SKyle Evans #include <libecc/nn/nn_div_public.h>
18*f0865ec9SKyle Evans #include <libecc/nn/nn_logical.h>
19*f0865ec9SKyle Evans #include <libecc/nn/nn_add.h>
20*f0865ec9SKyle Evans #include <libecc/nn/nn_mod_pow.h>
21*f0865ec9SKyle Evans #include <libecc/nn/nn.h>
22*f0865ec9SKyle Evans /* Include the "internal" header as we use non public API here */
23*f0865ec9SKyle Evans #include "../nn/nn_mul.h"
24*f0865ec9SKyle Evans
25*f0865ec9SKyle Evans /*
26*f0865ec9SKyle Evans * Compute out = x^-1 mod m, i.e. out such that (out * x) = 1 mod m
27*f0865ec9SKyle Evans * out is initialized by the function, i.e. caller needs not initialize
28*f0865ec9SKyle Evans * it; only provide the associated storage space. Done in *constant
29*f0865ec9SKyle Evans * time* if underlying routines are.
30*f0865ec9SKyle Evans *
31*f0865ec9SKyle Evans * Asserts that m is odd and that x is smaller than m.
32*f0865ec9SKyle Evans * This second condition is not strictly necessary,
33*f0865ec9SKyle Evans * but it allows to perform all operations on nn's of the same length,
34*f0865ec9SKyle Evans * namely the length of m.
35*f0865ec9SKyle Evans *
36*f0865ec9SKyle Evans * Uses a binary xgcd algorithm,
37*f0865ec9SKyle Evans * only keeps track of coefficient for inverting x,
38*f0865ec9SKyle Evans * and performs reduction modulo m at each step.
39*f0865ec9SKyle Evans *
40*f0865ec9SKyle Evans * This does not normalize out on return.
41*f0865ec9SKyle Evans *
42*f0865ec9SKyle Evans * 0 is returned on success (everything went ok and x has reciprocal), -1
43*f0865ec9SKyle Evans * on error or if x has no reciprocal. On error, out is not meaningful.
44*f0865ec9SKyle Evans *
45*f0865ec9SKyle Evans * The function is an internal helper: caller MUST check params have been
46*f0865ec9SKyle Evans * initialized, i.e. this is not done by the function.
47*f0865ec9SKyle Evans *
48*f0865ec9SKyle Evans */
_nn_modinv_odd(nn_t out,nn_src_t x,nn_src_t m)49*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int _nn_modinv_odd(nn_t out, nn_src_t x, nn_src_t m)
50*f0865ec9SKyle Evans {
51*f0865ec9SKyle Evans int isodd, swap, smaller, ret, cmp, iszero, tmp_isodd;
52*f0865ec9SKyle Evans nn a, b, u, tmp, mp1d2;
53*f0865ec9SKyle Evans nn_t uu = out;
54*f0865ec9SKyle Evans bitcnt_t cnt;
55*f0865ec9SKyle Evans a.magic = b.magic = u.magic = tmp.magic = mp1d2.magic = WORD(0);
56*f0865ec9SKyle Evans
57*f0865ec9SKyle Evans ret = nn_init(out, 0); EG(ret, err);
58*f0865ec9SKyle Evans ret = nn_init(&a, (u16)(m->wlen * WORD_BYTES)); EG(ret, err);
59*f0865ec9SKyle Evans ret = nn_init(&b, (u16)(m->wlen * WORD_BYTES)); EG(ret, err);
60*f0865ec9SKyle Evans ret = nn_init(&u, (u16)(m->wlen * WORD_BYTES)); EG(ret, err);
61*f0865ec9SKyle Evans ret = nn_init(&mp1d2, (u16)(m->wlen * WORD_BYTES)); EG(ret, err);
62*f0865ec9SKyle Evans /*
63*f0865ec9SKyle Evans * Temporary space needed to only deal with positive stuff.
64*f0865ec9SKyle Evans */
65*f0865ec9SKyle Evans ret = nn_init(&tmp, (u16)(m->wlen * WORD_BYTES)); EG(ret, err);
66*f0865ec9SKyle Evans
67*f0865ec9SKyle Evans MUST_HAVE((!nn_isodd(m, &isodd)) && isodd, ret, err);
68*f0865ec9SKyle Evans MUST_HAVE((!nn_cmp(x, m, &cmp)) && (cmp < 0), ret, err);
69*f0865ec9SKyle Evans MUST_HAVE((!nn_iszero(x, &iszero)) && (!iszero), ret, err);
70*f0865ec9SKyle Evans
71*f0865ec9SKyle Evans /*
72*f0865ec9SKyle Evans * Maintain:
73*f0865ec9SKyle Evans *
74*f0865ec9SKyle Evans * a = u * x (mod m)
75*f0865ec9SKyle Evans * b = uu * x (mod m)
76*f0865ec9SKyle Evans *
77*f0865ec9SKyle Evans * and b odd at all times. Initially,
78*f0865ec9SKyle Evans *
79*f0865ec9SKyle Evans * a = x, u = 1
80*f0865ec9SKyle Evans * b = m, uu = 0
81*f0865ec9SKyle Evans */
82*f0865ec9SKyle Evans ret = nn_copy(&a, x); EG(ret, err);
83*f0865ec9SKyle Evans ret = nn_set_wlen(&a, m->wlen); EG(ret, err);
84*f0865ec9SKyle Evans ret = nn_copy(&b, m); EG(ret, err);
85*f0865ec9SKyle Evans ret = nn_one(&u); EG(ret, err);
86*f0865ec9SKyle Evans ret = nn_zero(uu); EG(ret, err);
87*f0865ec9SKyle Evans
88*f0865ec9SKyle Evans /*
89*f0865ec9SKyle Evans * The lengths of u and uu should not affect constant timeness but it
90*f0865ec9SKyle Evans * does not hurt to set them already.
91*f0865ec9SKyle Evans * They will always be strictly smaller than m.
92*f0865ec9SKyle Evans */
93*f0865ec9SKyle Evans ret = nn_set_wlen(&u, m->wlen); EG(ret, err);
94*f0865ec9SKyle Evans ret = nn_set_wlen(uu, m->wlen); EG(ret, err);
95*f0865ec9SKyle Evans
96*f0865ec9SKyle Evans /*
97*f0865ec9SKyle Evans * Precompute inverse of 2 mod m:
98*f0865ec9SKyle Evans * 2^-1 = (m+1)/2
99*f0865ec9SKyle Evans * computed as (m >> 1) + 1.
100*f0865ec9SKyle Evans */
101*f0865ec9SKyle Evans ret = nn_rshift_fixedlen(&mp1d2, m, 1); EG(ret, err);
102*f0865ec9SKyle Evans
103*f0865ec9SKyle Evans ret = nn_inc(&mp1d2, &mp1d2); EG(ret, err); /* no carry can occur here
104*f0865ec9SKyle Evans because of prev. shift */
105*f0865ec9SKyle Evans
106*f0865ec9SKyle Evans cnt = (bitcnt_t)((a.wlen + b.wlen) * WORD_BITS);
107*f0865ec9SKyle Evans while (cnt > 0) {
108*f0865ec9SKyle Evans cnt = (bitcnt_t)(cnt - 1);
109*f0865ec9SKyle Evans /*
110*f0865ec9SKyle Evans * Always maintain b odd. The logic of the iteration is as
111*f0865ec9SKyle Evans * follows.
112*f0865ec9SKyle Evans */
113*f0865ec9SKyle Evans
114*f0865ec9SKyle Evans /*
115*f0865ec9SKyle Evans * For a, b:
116*f0865ec9SKyle Evans *
117*f0865ec9SKyle Evans * odd = a & 1
118*f0865ec9SKyle Evans * swap = odd & (a < b)
119*f0865ec9SKyle Evans * if (swap)
120*f0865ec9SKyle Evans * swap(a, b)
121*f0865ec9SKyle Evans * if (odd)
122*f0865ec9SKyle Evans * a -= b
123*f0865ec9SKyle Evans * a /= 2
124*f0865ec9SKyle Evans */
125*f0865ec9SKyle Evans
126*f0865ec9SKyle Evans MUST_HAVE((!nn_isodd(&b, &tmp_isodd)) && tmp_isodd, ret, err);
127*f0865ec9SKyle Evans
128*f0865ec9SKyle Evans ret = nn_isodd(&a, &isodd); EG(ret, err);
129*f0865ec9SKyle Evans ret = nn_cmp(&a, &b, &cmp); EG(ret, err);
130*f0865ec9SKyle Evans swap = isodd & (cmp == -1);
131*f0865ec9SKyle Evans
132*f0865ec9SKyle Evans ret = nn_cnd_swap(swap, &a, &b); EG(ret, err);
133*f0865ec9SKyle Evans ret = nn_cnd_sub(isodd, &a, &a, &b); EG(ret, err);
134*f0865ec9SKyle Evans
135*f0865ec9SKyle Evans MUST_HAVE((!nn_isodd(&a, &tmp_isodd)) && (!tmp_isodd), ret, err); /* a is now even */
136*f0865ec9SKyle Evans
137*f0865ec9SKyle Evans ret = nn_rshift_fixedlen(&a, &a, 1); EG(ret, err);/* division by 2 */
138*f0865ec9SKyle Evans
139*f0865ec9SKyle Evans /*
140*f0865ec9SKyle Evans * For u, uu:
141*f0865ec9SKyle Evans *
142*f0865ec9SKyle Evans * if (swap)
143*f0865ec9SKyle Evans * swap u, uu
144*f0865ec9SKyle Evans * smaller = (u < uu)
145*f0865ec9SKyle Evans * if (odd)
146*f0865ec9SKyle Evans * if (smaller)
147*f0865ec9SKyle Evans * u += m - uu
148*f0865ec9SKyle Evans * else
149*f0865ec9SKyle Evans * u -= uu
150*f0865ec9SKyle Evans * u >>= 1
151*f0865ec9SKyle Evans * if (u was odd)
152*f0865ec9SKyle Evans * u += (m+1)/2
153*f0865ec9SKyle Evans */
154*f0865ec9SKyle Evans ret = nn_cnd_swap(swap, &u, uu); EG(ret, err);
155*f0865ec9SKyle Evans
156*f0865ec9SKyle Evans /* This parameter is used to avoid handling negative numbers. */
157*f0865ec9SKyle Evans ret = nn_cmp(&u, uu, &cmp); EG(ret, err);
158*f0865ec9SKyle Evans smaller = (cmp == -1);
159*f0865ec9SKyle Evans
160*f0865ec9SKyle Evans /* Computation of 'm - uu' can always be performed. */
161*f0865ec9SKyle Evans ret = nn_sub(&tmp, m, uu); EG(ret, err);
162*f0865ec9SKyle Evans
163*f0865ec9SKyle Evans /* Selection btw 'm-uu' and '-uu' is made by the following function calls. */
164*f0865ec9SKyle Evans ret = nn_cnd_add(isodd & smaller, &u, &u, &tmp); EG(ret, err); /* no carry can occur as 'u+(m-uu) = m-(uu-u) < m' */
165*f0865ec9SKyle Evans ret = nn_cnd_sub(isodd & (!smaller), &u, &u, uu); EG(ret, err);
166*f0865ec9SKyle Evans
167*f0865ec9SKyle Evans /* Divide u by 2 */
168*f0865ec9SKyle Evans ret = nn_isodd(&u, &isodd); EG(ret, err);
169*f0865ec9SKyle Evans ret = nn_rshift_fixedlen(&u, &u, 1); EG(ret, err);
170*f0865ec9SKyle Evans ret = nn_cnd_add(isodd, &u, &u, &mp1d2); EG(ret, err); /* no carry can occur as u=1+u' with u'<m-1 and u' even so u'/2+(m+1)/2<(m-1)/2+(m+1)/2=m */
171*f0865ec9SKyle Evans
172*f0865ec9SKyle Evans MUST_HAVE((!nn_cmp(&u, m, &cmp)) && (cmp < 0), ret, err);
173*f0865ec9SKyle Evans MUST_HAVE((!nn_cmp(uu, m, &cmp)) && (cmp < 0), ret, err);
174*f0865ec9SKyle Evans
175*f0865ec9SKyle Evans /*
176*f0865ec9SKyle Evans * As long as a > 0, the quantity
177*f0865ec9SKyle Evans * (bitsize of a) + (bitsize of b)
178*f0865ec9SKyle Evans * is reduced by at least one bit per iteration,
179*f0865ec9SKyle Evans * hence after (bitsize of x) + (bitsize of m) - 1
180*f0865ec9SKyle Evans * iterations we surely have a = 0. Then b = gcd(x, m)
181*f0865ec9SKyle Evans * and if b = 1 then also uu = x^{-1} (mod m).
182*f0865ec9SKyle Evans */
183*f0865ec9SKyle Evans }
184*f0865ec9SKyle Evans
185*f0865ec9SKyle Evans MUST_HAVE((!nn_iszero(&a, &iszero)) && iszero, ret, err);
186*f0865ec9SKyle Evans
187*f0865ec9SKyle Evans /* Check that gcd is one. */
188*f0865ec9SKyle Evans ret = nn_cmp_word(&b, WORD(1), &cmp); EG(ret, err);
189*f0865ec9SKyle Evans
190*f0865ec9SKyle Evans /* If not, set "inverse" to zero. */
191*f0865ec9SKyle Evans ret = nn_cnd_sub(cmp != 0, uu, uu, uu); EG(ret, err);
192*f0865ec9SKyle Evans
193*f0865ec9SKyle Evans ret = cmp ? -1 : 0;
194*f0865ec9SKyle Evans
195*f0865ec9SKyle Evans err:
196*f0865ec9SKyle Evans nn_uninit(&a);
197*f0865ec9SKyle Evans nn_uninit(&b);
198*f0865ec9SKyle Evans nn_uninit(&u);
199*f0865ec9SKyle Evans nn_uninit(&mp1d2);
200*f0865ec9SKyle Evans nn_uninit(&tmp);
201*f0865ec9SKyle Evans
202*f0865ec9SKyle Evans PTR_NULLIFY(uu);
203*f0865ec9SKyle Evans
204*f0865ec9SKyle Evans return ret;
205*f0865ec9SKyle Evans }
206*f0865ec9SKyle Evans
207*f0865ec9SKyle Evans /*
208*f0865ec9SKyle Evans * Same as above without restriction on m.
209*f0865ec9SKyle Evans * No attempt to make it constant time.
210*f0865ec9SKyle Evans * Uses the above constant-time binary xgcd when m is odd
211*f0865ec9SKyle Evans * and a not constant time plain Euclidean xgcd when m is even.
212*f0865ec9SKyle Evans *
213*f0865ec9SKyle Evans * _out parameter need not be initialized; this will be done by the function.
214*f0865ec9SKyle Evans * x and m must be initialized nn.
215*f0865ec9SKyle Evans *
216*f0865ec9SKyle Evans * Return -1 on error or if if x has no reciprocal modulo m. out is zeroed.
217*f0865ec9SKyle Evans * Return 0 if x has reciprocal modulo m.
218*f0865ec9SKyle Evans *
219*f0865ec9SKyle Evans * The function supports aliasing.
220*f0865ec9SKyle Evans */
nn_modinv(nn_t _out,nn_src_t x,nn_src_t m)221*f0865ec9SKyle Evans int nn_modinv(nn_t _out, nn_src_t x, nn_src_t m)
222*f0865ec9SKyle Evans {
223*f0865ec9SKyle Evans int sign, ret, cmp, isodd, isone;
224*f0865ec9SKyle Evans nn_t x_mod_m;
225*f0865ec9SKyle Evans nn u, v, out; /* Out to support aliasing */
226*f0865ec9SKyle Evans out.magic = u.magic = v.magic = WORD(0);
227*f0865ec9SKyle Evans
228*f0865ec9SKyle Evans ret = nn_check_initialized(x); EG(ret, err);
229*f0865ec9SKyle Evans ret = nn_check_initialized(m); EG(ret, err);
230*f0865ec9SKyle Evans
231*f0865ec9SKyle Evans /* Initialize out */
232*f0865ec9SKyle Evans ret = nn_init(&out, 0); EG(ret, err);
233*f0865ec9SKyle Evans ret = nn_isodd(m, &isodd); EG(ret, err);
234*f0865ec9SKyle Evans if (isodd) {
235*f0865ec9SKyle Evans ret = nn_cmp(x, m, &cmp); EG(ret, err);
236*f0865ec9SKyle Evans if (cmp >= 0) {
237*f0865ec9SKyle Evans /*
238*f0865ec9SKyle Evans * If x >= m, (x^-1) mod m = ((x mod m)^-1) mod m
239*f0865ec9SKyle Evans * Hence, compute x mod m. In order to avoid
240*f0865ec9SKyle Evans * additional stack usage, we use 'u' (not
241*f0865ec9SKyle Evans * already useful at that point in the function).
242*f0865ec9SKyle Evans */
243*f0865ec9SKyle Evans x_mod_m = &u;
244*f0865ec9SKyle Evans ret = nn_mod(x_mod_m, x, m); EG(ret, err);
245*f0865ec9SKyle Evans ret = _nn_modinv_odd(&out, x_mod_m, m); EG(ret, err);
246*f0865ec9SKyle Evans } else {
247*f0865ec9SKyle Evans ret = _nn_modinv_odd(&out, x, m); EG(ret, err);
248*f0865ec9SKyle Evans }
249*f0865ec9SKyle Evans ret = nn_copy(_out, &out);
250*f0865ec9SKyle Evans goto err;
251*f0865ec9SKyle Evans }
252*f0865ec9SKyle Evans
253*f0865ec9SKyle Evans /* Now m is even */
254*f0865ec9SKyle Evans ret = nn_isodd(x, &isodd); EG(ret, err);
255*f0865ec9SKyle Evans MUST_HAVE(isodd, ret, err);
256*f0865ec9SKyle Evans
257*f0865ec9SKyle Evans ret = nn_init(&u, 0); EG(ret, err);
258*f0865ec9SKyle Evans ret = nn_init(&v, 0); EG(ret, err);
259*f0865ec9SKyle Evans ret = nn_xgcd(&out, &u, &v, x, m, &sign); EG(ret, err);
260*f0865ec9SKyle Evans ret = nn_isone(&out, &isone); EG(ret, err);
261*f0865ec9SKyle Evans MUST_HAVE(isone, ret, err);
262*f0865ec9SKyle Evans
263*f0865ec9SKyle Evans ret = nn_mod(&out, &u, m); EG(ret, err);
264*f0865ec9SKyle Evans if (sign == -1) {
265*f0865ec9SKyle Evans ret = nn_sub(&out, m, &out); EG(ret, err);
266*f0865ec9SKyle Evans }
267*f0865ec9SKyle Evans ret = nn_copy(_out, &out);
268*f0865ec9SKyle Evans
269*f0865ec9SKyle Evans err:
270*f0865ec9SKyle Evans nn_uninit(&out);
271*f0865ec9SKyle Evans nn_uninit(&u);
272*f0865ec9SKyle Evans nn_uninit(&v);
273*f0865ec9SKyle Evans
274*f0865ec9SKyle Evans PTR_NULLIFY(x_mod_m);
275*f0865ec9SKyle Evans
276*f0865ec9SKyle Evans return ret;
277*f0865ec9SKyle Evans }
278*f0865ec9SKyle Evans
279*f0865ec9SKyle Evans /*
280*f0865ec9SKyle Evans * Compute (A - B) % 2^(storagebitsizeof(B) + 1). A and B must be initialized nn.
281*f0865ec9SKyle Evans * the function is an internal helper and does not verify params have been
282*f0865ec9SKyle Evans * initialized; this must be done by the caller. No assumption on A and B values
283*f0865ec9SKyle Evans * such as A >= B. Done in *constant time. Returns 0 on success, -1 on error.
284*f0865ec9SKyle Evans */
_nn_sub_mod_2exp(nn_t A,nn_src_t B)285*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static inline int _nn_sub_mod_2exp(nn_t A, nn_src_t B)
286*f0865ec9SKyle Evans {
287*f0865ec9SKyle Evans u8 Awlen = A->wlen;
288*f0865ec9SKyle Evans int ret;
289*f0865ec9SKyle Evans
290*f0865ec9SKyle Evans ret = nn_set_wlen(A, (u8)(Awlen + 1)); EG(ret, err);
291*f0865ec9SKyle Evans
292*f0865ec9SKyle Evans /* Make sure A > B */
293*f0865ec9SKyle Evans /* NOTE: A->wlen - 1 is not an issue here thant to the nn_set_wlen above */
294*f0865ec9SKyle Evans A->val[A->wlen - 1] = WORD(1);
295*f0865ec9SKyle Evans ret = nn_sub(A, A, B); EG(ret, err);
296*f0865ec9SKyle Evans
297*f0865ec9SKyle Evans /* The artificial word will be cleared in the following function call */
298*f0865ec9SKyle Evans ret = nn_set_wlen(A, Awlen);
299*f0865ec9SKyle Evans
300*f0865ec9SKyle Evans err:
301*f0865ec9SKyle Evans return ret;
302*f0865ec9SKyle Evans }
303*f0865ec9SKyle Evans
304*f0865ec9SKyle Evans /*
305*f0865ec9SKyle Evans * Invert x modulo 2^exp using Hensel lifting. Returns 0 on success, -1 on
306*f0865ec9SKyle Evans * error. On success, x_isodd is 1 if x is odd, 0 if it is even.
307*f0865ec9SKyle Evans * Please note that the result is correct (inverse of x) only when x is prime
308*f0865ec9SKyle Evans * to 2^exp, i.e. x is odd (x_odd is 1).
309*f0865ec9SKyle Evans *
310*f0865ec9SKyle Evans * Operations are done in *constant time*.
311*f0865ec9SKyle Evans *
312*f0865ec9SKyle Evans * Aliasing is supported.
313*f0865ec9SKyle Evans */
nn_modinv_2exp(nn_t _out,nn_src_t x,bitcnt_t exp,int * x_isodd)314*f0865ec9SKyle Evans int nn_modinv_2exp(nn_t _out, nn_src_t x, bitcnt_t exp, int *x_isodd)
315*f0865ec9SKyle Evans {
316*f0865ec9SKyle Evans bitcnt_t cnt;
317*f0865ec9SKyle Evans u8 exp_wlen = (u8)BIT_LEN_WORDS(exp);
318*f0865ec9SKyle Evans bitcnt_t exp_cnt = exp % WORD_BITS;
319*f0865ec9SKyle Evans word_t mask = (word_t)((exp_cnt == 0) ? WORD_MASK : (word_t)((WORD(1) << exp_cnt) - WORD(1)));
320*f0865ec9SKyle Evans nn tmp_sqr, tmp_mul;
321*f0865ec9SKyle Evans /* for aliasing */
322*f0865ec9SKyle Evans int isodd, ret;
323*f0865ec9SKyle Evans nn out;
324*f0865ec9SKyle Evans out.magic = tmp_sqr.magic = tmp_mul.magic = WORD(0);
325*f0865ec9SKyle Evans
326*f0865ec9SKyle Evans MUST_HAVE((x_isodd != NULL), ret, err);
327*f0865ec9SKyle Evans ret = nn_check_initialized(x); EG(ret, err);
328*f0865ec9SKyle Evans ret = nn_check_initialized(_out); EG(ret, err);
329*f0865ec9SKyle Evans
330*f0865ec9SKyle Evans ret = nn_init(&out, 0); EG(ret, err);
331*f0865ec9SKyle Evans ret = nn_init(&tmp_sqr, 0); EG(ret, err);
332*f0865ec9SKyle Evans ret = nn_init(&tmp_mul, 0); EG(ret, err);
333*f0865ec9SKyle Evans ret = nn_isodd(x, &isodd); EG(ret, err);
334*f0865ec9SKyle Evans if (exp == (bitcnt_t)0){
335*f0865ec9SKyle Evans /* Specific case of zero exponent, output 0 */
336*f0865ec9SKyle Evans (*x_isodd) = isodd;
337*f0865ec9SKyle Evans goto err;
338*f0865ec9SKyle Evans }
339*f0865ec9SKyle Evans if (!isodd) {
340*f0865ec9SKyle Evans ret = nn_zero(_out); EG(ret, err);
341*f0865ec9SKyle Evans (*x_isodd) = 0;
342*f0865ec9SKyle Evans goto err;
343*f0865ec9SKyle Evans }
344*f0865ec9SKyle Evans
345*f0865ec9SKyle Evans /*
346*f0865ec9SKyle Evans * Inverse modulo 2.
347*f0865ec9SKyle Evans */
348*f0865ec9SKyle Evans cnt = 1;
349*f0865ec9SKyle Evans ret = nn_one(&out); EG(ret, err);
350*f0865ec9SKyle Evans
351*f0865ec9SKyle Evans /*
352*f0865ec9SKyle Evans * Inverse modulo 2^(2^i) <= 2^WORD_BITS.
353*f0865ec9SKyle Evans * Assumes WORD_BITS is a power of two.
354*f0865ec9SKyle Evans */
355*f0865ec9SKyle Evans for (; cnt < WORD_MIN(WORD_BITS, exp); cnt = (bitcnt_t)(cnt << 1)) {
356*f0865ec9SKyle Evans ret = nn_sqr_low(&tmp_sqr, &out, out.wlen); EG(ret, err);
357*f0865ec9SKyle Evans ret = nn_mul_low(&tmp_mul, &tmp_sqr, x, out.wlen); EG(ret, err);
358*f0865ec9SKyle Evans ret = nn_lshift_fixedlen(&out, &out, 1); EG(ret, err);
359*f0865ec9SKyle Evans
360*f0865ec9SKyle Evans /*
361*f0865ec9SKyle Evans * Allowing "negative" results for a subtraction modulo
362*f0865ec9SKyle Evans * a power of two would allow to use directly:
363*f0865ec9SKyle Evans * nn_sub(out, out, tmp_mul)
364*f0865ec9SKyle Evans * which is always negative in ZZ except when x is one.
365*f0865ec9SKyle Evans *
366*f0865ec9SKyle Evans * Another solution is to add the opposite of tmp_mul.
367*f0865ec9SKyle Evans * nn_modopp_2exp(tmp_mul, tmp_mul);
368*f0865ec9SKyle Evans * nn_add(out, out, tmp_mul);
369*f0865ec9SKyle Evans *
370*f0865ec9SKyle Evans * The current solution is to add a sufficiently large power
371*f0865ec9SKyle Evans * of two to out unconditionally to absorb the potential
372*f0865ec9SKyle Evans * borrow. The result modulo 2^(2^i) is correct whether the
373*f0865ec9SKyle Evans * borrow occurs or not.
374*f0865ec9SKyle Evans */
375*f0865ec9SKyle Evans ret = _nn_sub_mod_2exp(&out, &tmp_mul); EG(ret, err);
376*f0865ec9SKyle Evans }
377*f0865ec9SKyle Evans
378*f0865ec9SKyle Evans /*
379*f0865ec9SKyle Evans * Inverse modulo 2^WORD_BITS < 2^(2^i) < 2^exp.
380*f0865ec9SKyle Evans */
381*f0865ec9SKyle Evans for (; cnt < ((exp + 1) >> 1); cnt = (bitcnt_t)(cnt << 1)) {
382*f0865ec9SKyle Evans ret = nn_set_wlen(&out, (u8)(2 * out.wlen)); EG(ret, err);
383*f0865ec9SKyle Evans ret = nn_sqr_low(&tmp_sqr, &out, out.wlen); EG(ret, err);
384*f0865ec9SKyle Evans ret = nn_mul_low(&tmp_mul, &tmp_sqr, x, out.wlen); EG(ret, err);
385*f0865ec9SKyle Evans ret = nn_lshift_fixedlen(&out, &out, 1); EG(ret, err);
386*f0865ec9SKyle Evans ret = _nn_sub_mod_2exp(&out, &tmp_mul); EG(ret, err);
387*f0865ec9SKyle Evans }
388*f0865ec9SKyle Evans
389*f0865ec9SKyle Evans /*
390*f0865ec9SKyle Evans * Inverse modulo 2^(2^i + j) >= 2^exp.
391*f0865ec9SKyle Evans */
392*f0865ec9SKyle Evans if (exp > WORD_BITS) {
393*f0865ec9SKyle Evans ret = nn_set_wlen(&out, exp_wlen); EG(ret, err);
394*f0865ec9SKyle Evans ret = nn_sqr_low(&tmp_sqr, &out, out.wlen); EG(ret, err);
395*f0865ec9SKyle Evans ret = nn_mul_low(&tmp_mul, &tmp_sqr, x, out.wlen); EG(ret, err);
396*f0865ec9SKyle Evans ret = nn_lshift_fixedlen(&out, &out, 1); EG(ret, err);
397*f0865ec9SKyle Evans ret = _nn_sub_mod_2exp(&out, &tmp_mul); EG(ret, err);
398*f0865ec9SKyle Evans }
399*f0865ec9SKyle Evans
400*f0865ec9SKyle Evans /*
401*f0865ec9SKyle Evans * Inverse modulo 2^exp.
402*f0865ec9SKyle Evans */
403*f0865ec9SKyle Evans out.val[exp_wlen - 1] &= mask;
404*f0865ec9SKyle Evans
405*f0865ec9SKyle Evans ret = nn_copy(_out, &out); EG(ret, err);
406*f0865ec9SKyle Evans
407*f0865ec9SKyle Evans (*x_isodd) = 1;
408*f0865ec9SKyle Evans
409*f0865ec9SKyle Evans err:
410*f0865ec9SKyle Evans nn_uninit(&out);
411*f0865ec9SKyle Evans nn_uninit(&tmp_sqr);
412*f0865ec9SKyle Evans nn_uninit(&tmp_mul);
413*f0865ec9SKyle Evans
414*f0865ec9SKyle Evans return ret;
415*f0865ec9SKyle Evans }
416*f0865ec9SKyle Evans
417*f0865ec9SKyle Evans /*
418*f0865ec9SKyle Evans * Invert word w modulo m.
419*f0865ec9SKyle Evans *
420*f0865ec9SKyle Evans * The function supports aliasing.
421*f0865ec9SKyle Evans */
nn_modinv_word(nn_t out,word_t w,nn_src_t m)422*f0865ec9SKyle Evans int nn_modinv_word(nn_t out, word_t w, nn_src_t m)
423*f0865ec9SKyle Evans {
424*f0865ec9SKyle Evans nn nn_tmp;
425*f0865ec9SKyle Evans int ret;
426*f0865ec9SKyle Evans nn_tmp.magic = WORD(0);
427*f0865ec9SKyle Evans
428*f0865ec9SKyle Evans ret = nn_init(&nn_tmp, 0); EG(ret, err);
429*f0865ec9SKyle Evans ret = nn_set_word_value(&nn_tmp, w); EG(ret, err);
430*f0865ec9SKyle Evans ret = nn_modinv(out, &nn_tmp, m);
431*f0865ec9SKyle Evans
432*f0865ec9SKyle Evans err:
433*f0865ec9SKyle Evans nn_uninit(&nn_tmp);
434*f0865ec9SKyle Evans
435*f0865ec9SKyle Evans return ret;
436*f0865ec9SKyle Evans }
437*f0865ec9SKyle Evans
438*f0865ec9SKyle Evans
439*f0865ec9SKyle Evans /*
440*f0865ec9SKyle Evans * Internal function for nn_modinv_fermat and nn_modinv_fermat_redc used
441*f0865ec9SKyle Evans * hereafter.
442*f0865ec9SKyle Evans */
_nn_modinv_fermat_common(nn_t out,nn_src_t x,nn_src_t p,nn_t p_minus_two,int * lesstwo)443*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int _nn_modinv_fermat_common(nn_t out, nn_src_t x, nn_src_t p, nn_t p_minus_two, int *lesstwo)
444*f0865ec9SKyle Evans {
445*f0865ec9SKyle Evans int ret, cmp, isodd;
446*f0865ec9SKyle Evans nn two;
447*f0865ec9SKyle Evans two.magic = WORD(0);
448*f0865ec9SKyle Evans
449*f0865ec9SKyle Evans /* Sanity checks on inputs */
450*f0865ec9SKyle Evans ret = nn_check_initialized(x); EG(ret, err);
451*f0865ec9SKyle Evans ret = nn_check_initialized(p); EG(ret, err);
452*f0865ec9SKyle Evans /* NOTE: since this is an internal function, we are ensured that p_minus_two,
453*f0865ec9SKyle Evans * two and regular are OK.
454*f0865ec9SKyle Evans */
455*f0865ec9SKyle Evans
456*f0865ec9SKyle Evans /* 0 is not invertible in any case */
457*f0865ec9SKyle Evans ret = nn_iszero(x, &cmp); EG(ret, err);
458*f0865ec9SKyle Evans if(cmp){
459*f0865ec9SKyle Evans /* Zero the output and return an error */
460*f0865ec9SKyle Evans ret = nn_init(out, 0); EG(ret, err);
461*f0865ec9SKyle Evans ret = nn_zero(out); EG(ret, err);
462*f0865ec9SKyle Evans ret = -1;
463*f0865ec9SKyle Evans goto err;
464*f0865ec9SKyle Evans }
465*f0865ec9SKyle Evans
466*f0865ec9SKyle Evans /* For p <= 2, p being prime either p = 1 or p = 2.
467*f0865ec9SKyle Evans * When p = 2, only 1 has an inverse, if p = 1 no one has an inverse.
468*f0865ec9SKyle Evans */
469*f0865ec9SKyle Evans (*lesstwo) = 0;
470*f0865ec9SKyle Evans ret = nn_cmp_word(p, WORD(2), &cmp); EG(ret, err);
471*f0865ec9SKyle Evans if(cmp == 0){
472*f0865ec9SKyle Evans /* This is the p = 2 case, parity of x provides the result */
473*f0865ec9SKyle Evans ret = nn_isodd(x, &isodd); EG(ret, err);
474*f0865ec9SKyle Evans if(isodd){
475*f0865ec9SKyle Evans /* x is odd, 1 is its inverse */
476*f0865ec9SKyle Evans ret = nn_init(out, 0); EG(ret, err);
477*f0865ec9SKyle Evans ret = nn_one(out); EG(ret, err);
478*f0865ec9SKyle Evans ret = 0;
479*f0865ec9SKyle Evans }
480*f0865ec9SKyle Evans else{
481*f0865ec9SKyle Evans /* x is even, no inverse. Zero the output */
482*f0865ec9SKyle Evans ret = nn_init(out, 0); EG(ret, err);
483*f0865ec9SKyle Evans ret = nn_zero(out); EG(ret, err);
484*f0865ec9SKyle Evans ret = -1;
485*f0865ec9SKyle Evans }
486*f0865ec9SKyle Evans (*lesstwo) = 1;
487*f0865ec9SKyle Evans goto err;
488*f0865ec9SKyle Evans } else if (cmp < 0){
489*f0865ec9SKyle Evans /* This is the p = 1 case, no inverse here: hence return an error */
490*f0865ec9SKyle Evans /* Zero the output */
491*f0865ec9SKyle Evans ret = nn_init(out, 0); EG(ret, err);
492*f0865ec9SKyle Evans ret = nn_zero(out); EG(ret, err);
493*f0865ec9SKyle Evans ret = -1;
494*f0865ec9SKyle Evans (*lesstwo) = 1;
495*f0865ec9SKyle Evans goto err;
496*f0865ec9SKyle Evans }
497*f0865ec9SKyle Evans
498*f0865ec9SKyle Evans /* Else we compute (p-2) for the upper layer */
499*f0865ec9SKyle Evans if(p != p_minus_two){
500*f0865ec9SKyle Evans /* Handle aliasing of p and p_minus_two */
501*f0865ec9SKyle Evans ret = nn_init(p_minus_two, 0); EG(ret, err);
502*f0865ec9SKyle Evans }
503*f0865ec9SKyle Evans
504*f0865ec9SKyle Evans ret = nn_init(&two, 0); EG(ret, err);
505*f0865ec9SKyle Evans ret = nn_set_word_value(&two, WORD(2)); EG(ret, err);
506*f0865ec9SKyle Evans ret = nn_sub(p_minus_two, p, &two);
507*f0865ec9SKyle Evans
508*f0865ec9SKyle Evans err:
509*f0865ec9SKyle Evans nn_uninit(&two);
510*f0865ec9SKyle Evans
511*f0865ec9SKyle Evans return ret;
512*f0865ec9SKyle Evans }
513*f0865ec9SKyle Evans
514*f0865ec9SKyle Evans /*
515*f0865ec9SKyle Evans * Invert NN x modulo p using Fermat's little theorem for our inversion:
516*f0865ec9SKyle Evans *
517*f0865ec9SKyle Evans * p prime means that:
518*f0865ec9SKyle Evans * x^(p-1) = 1 mod (p)
519*f0865ec9SKyle Evans * which means that x^(p-2) mod(p) is the modular inverse of x mod (p)
520*f0865ec9SKyle Evans * for x != 0
521*f0865ec9SKyle Evans *
522*f0865ec9SKyle Evans * NOTE: the input hypothesis is that p is prime.
523*f0865ec9SKyle Evans * XXX WARNING: using this function with p not prime will produce wrong
524*f0865ec9SKyle Evans * results without triggering an error!
525*f0865ec9SKyle Evans *
526*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error
527*f0865ec9SKyle Evans * (e.g. if x has no inverse modulo p, i.e. x = 0).
528*f0865ec9SKyle Evans *
529*f0865ec9SKyle Evans * Aliasing is supported.
530*f0865ec9SKyle Evans */
nn_modinv_fermat(nn_t out,nn_src_t x,nn_src_t p)531*f0865ec9SKyle Evans int nn_modinv_fermat(nn_t out, nn_src_t x, nn_src_t p)
532*f0865ec9SKyle Evans {
533*f0865ec9SKyle Evans int ret, lesstwo;
534*f0865ec9SKyle Evans nn p_minus_two;
535*f0865ec9SKyle Evans p_minus_two.magic = WORD(0);
536*f0865ec9SKyle Evans
537*f0865ec9SKyle Evans /* Call our helper.
538*f0865ec9SKyle Evans * NOTE: "marginal" cases where x = 0 and p <= 2 should be caught in this helper.
539*f0865ec9SKyle Evans */
540*f0865ec9SKyle Evans ret = _nn_modinv_fermat_common(out, x, p, &p_minus_two, &lesstwo); EG(ret, err);
541*f0865ec9SKyle Evans
542*f0865ec9SKyle Evans if(!lesstwo){
543*f0865ec9SKyle Evans /* Compute x^(p-2) mod (p) */
544*f0865ec9SKyle Evans ret = nn_mod_pow(out, x, &p_minus_two, p);
545*f0865ec9SKyle Evans }
546*f0865ec9SKyle Evans
547*f0865ec9SKyle Evans err:
548*f0865ec9SKyle Evans nn_uninit(&p_minus_two);
549*f0865ec9SKyle Evans
550*f0865ec9SKyle Evans return ret;
551*f0865ec9SKyle Evans }
552*f0865ec9SKyle Evans
553*f0865ec9SKyle Evans /*
554*f0865ec9SKyle Evans * Invert NN x modulo m using Fermat's little theorem for our inversion.
555*f0865ec9SKyle Evans *
556*f0865ec9SKyle Evans * This is a version with already (pre)computed Montgomery coefficients.
557*f0865ec9SKyle Evans *
558*f0865ec9SKyle Evans * NOTE: the input hypothesis is that p is prime.
559*f0865ec9SKyle Evans * XXX WARNING: using this function with p not prime will produce wrong
560*f0865ec9SKyle Evans * results without triggering an error!
561*f0865ec9SKyle Evans *
562*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error
563*f0865ec9SKyle Evans * (e.g. if x has no inverse modulo p, i.e. x = 0).
564*f0865ec9SKyle Evans *
565*f0865ec9SKyle Evans * Aliasing is supported.
566*f0865ec9SKyle Evans */
nn_modinv_fermat_redc(nn_t out,nn_src_t x,nn_src_t p,nn_src_t r,nn_src_t r_square,word_t mpinv)567*f0865ec9SKyle Evans int nn_modinv_fermat_redc(nn_t out, nn_src_t x, nn_src_t p, nn_src_t r, nn_src_t r_square, word_t mpinv)
568*f0865ec9SKyle Evans {
569*f0865ec9SKyle Evans int ret, lesstwo;
570*f0865ec9SKyle Evans nn p_minus_two;
571*f0865ec9SKyle Evans p_minus_two.magic = WORD(0);
572*f0865ec9SKyle Evans
573*f0865ec9SKyle Evans /* Call our helper.
574*f0865ec9SKyle Evans * NOTE: "marginal" cases where x = 0 and p <= 2 should be caught in this helper.
575*f0865ec9SKyle Evans */
576*f0865ec9SKyle Evans ret = _nn_modinv_fermat_common(out, x, p, &p_minus_two, &lesstwo); EG(ret, err);
577*f0865ec9SKyle Evans
578*f0865ec9SKyle Evans if(!lesstwo){
579*f0865ec9SKyle Evans /* Compute x^(p-2) mod (p) using precomputed Montgomery coefficients as input */
580*f0865ec9SKyle Evans ret = nn_mod_pow_redc(out, x, &p_minus_two, p, r, r_square, mpinv);
581*f0865ec9SKyle Evans }
582*f0865ec9SKyle Evans
583*f0865ec9SKyle Evans err:
584*f0865ec9SKyle Evans nn_uninit(&p_minus_two);
585*f0865ec9SKyle Evans
586*f0865ec9SKyle Evans return ret;
587*f0865ec9SKyle Evans }
588