xref: /freebsd/crypto/libecc/src/nn/nn_add.c (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
1 /*
2  *  Copyright (C) 2017 - This file is part of libecc project
3  *
4  *  Authors:
5  *      Ryad BENADJILA <ryadbenadjila@gmail.com>
6  *      Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7  *      Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr>
8  *
9  *  Contributors:
10  *      Nicolas VIVET <nicolas.vivet@ssi.gouv.fr>
11  *      Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr>
12  *
13  *  This software is licensed under a dual BSD and GPL v2 license.
14  *  See LICENSE file at the root folder of the project.
15  */
16 #include <libecc/nn/nn_add.h>
17 #include <libecc/nn/nn.h>
18 
19 /*
20  * This module provides conditional addition and subtraction functions between
21  * two nn:
22  *
23  *  o out = in1 +/- in2 if cnd is not zero.
24  *  o out = in1 if cnd is zero.
25  *
26  * The time taken by the operation does not depend on cnd value, i.e. it is
27  * constant time for that specific factor, nor on the values of in1 and in2.
28  * It still depends on the maximal length of in1 and in2.
29  *
30  * Common addition and subtraction functions are derived from those conditional
31  * versions.
32  */
33 
34 /*
35  * Conditionally adds 'in2' to 'in1' according to "cnd", storing the result
36  * in "out" and returning the carry in 'carry' parameter on success. This
37  * is the lowest level function for conditional addition. The function
38  * returns 0 on success, -1 on error.
39  *
40  * Note that unlike "usual" addition, the function is *in general* not
41  * commutative, i.e. "_nn_cnd_add(cnd, out, in1, in2)"  is not equivalent
42  * to "_nn_cnd_add(cnd, out, in2, in1)". It is commutative though if "cnd"
43  * is not zero or 'in1' == 'in2'.
44  *
45  * Aliasing of inputs and output is possible. "out" is initialized if needed,
46  * that is if not aliased to 'in1' or 'in2'. The length of "out" is set to
47  * the maximal length of 'in1' and 'in2'. Note that both 'in1' and 'in2' will
48  * be read to this maximal length. As our memory managment model assumes that
49  * storage arrays only contains zeros past the "wlen" index, correct results
50  * will be produced. The length of 'out' is not normalized on return.
51  *
52  * The runtime of this function should not depend on:
53  *  o the value of "cnd",
54  *  o the data stored in 'in1' and 'in2'.
55  * It depends on:
56  *  o the maximal length of 'in1' and 'in2'.
57  *
58  * This function is for internal use only.
59  */
_nn_cnd_add(int cnd,nn_t out,nn_src_t in1,nn_src_t in2,word_t * carry)60 ATTRIBUTE_WARN_UNUSED_RET static int _nn_cnd_add(int cnd, nn_t out, nn_src_t in1, nn_src_t in2,
61 		       word_t *carry)
62 {
63 	word_t tmp, carry1, carry2, _carry = WORD(0);
64 	word_t mask = WORD_MASK_IFNOTZERO(cnd);
65 	u8 i, loop_wlen;
66 	int ret;
67 
68 	MUST_HAVE((carry != NULL), ret, err);
69 	ret = nn_check_initialized(in1); EG(ret, err);
70 	ret = nn_check_initialized(in2); EG(ret, err);
71 
72 	/* Handle aliasing */
73 	loop_wlen = LOCAL_MAX(in1->wlen, in2->wlen);
74 	if ((out != in1) && (out != in2)) {
75 		ret = nn_init(out, (u16)(loop_wlen * WORD_BYTES)); EG(ret, err);
76 	} else {
77 		ret = nn_set_wlen(out, loop_wlen); EG(ret, err);
78 	}
79 
80 	/* Perform addition one word at a time, propagating the carry. */
81 	for (i = 0; i < loop_wlen; i++) {
82 		tmp = (word_t)(in1->val[i] + (in2->val[i] & mask));
83 		carry1 = (word_t)(tmp < in1->val[i]);
84 		out->val[i] = (word_t)(tmp + _carry);
85 		carry2 = (word_t)(out->val[i] < tmp);
86 		/* There is at most one carry going out. */
87 		_carry = (word_t)(carry1 | carry2);
88 	}
89 
90 	(*carry) = _carry;
91 
92 err:
93 	return ret;
94 }
95 
96 /*
97  * Conditionally adds 'in2' to 'in1' according to "cnd", storing the result
98  * in "out", including the potential carry overflowing past the maximal
99  * length of 'in1' and 'in2'. It is user responsibility to ensure that the
100  * resulting nn will not be higher than what can be supported. This is
101  * for instance guaranteed if both in1->wlen and in2->wlen are less than
102  * NN_MAX_WORD_LEN. Otherwise the function will error out which could leak
103  * information.
104  *
105  * Note that the length of the output depends the lengths of the inputs,
106  * but also on their values.
107  * It is the user responsibility to use this function carefully when
108  * constant time of an algorithm using this function is seeked.
109  * This choice was preferred above unconditionally increasing
110  * the length of the output by one, to ease the management of length
111  * explosion when multiple additions are performed.
112  * For finer carry propagation and length control the internal "_nn_cnd_add"
113  * function can be used.
114  *
115  * See "_nn_cnd_add" documentation above for further details.
116  *
117  * The function returns 0 on success, -1 on error.
118  */
nn_cnd_add(int cnd,nn_t out,nn_src_t in1,nn_src_t in2)119 int nn_cnd_add(int cnd, nn_t out, nn_src_t in1, nn_src_t in2)
120 {
121 	word_t carry;
122 	int ret;
123 
124 	ret = _nn_cnd_add(cnd, out, in1, in2, &carry); EG(ret, err);
125 
126 	/* We cannot allow a non-zero carry if out->wlen is at its limit */
127 	MUST_HAVE(((out->wlen != NN_MAX_WORD_LEN) || (!carry)), ret, err);
128 
129 	if (out->wlen != NN_MAX_WORD_LEN) {
130 		/*
131 		 * To maintain constant time, we perform carry addition in all
132 		 * cases. If carry is 0, no change is performed in practice,
133 		 * neither to 'out' value, nor to its length.
134 		 * Note that the length of the output can vary and make
135 		 * the time taken by further operations on it also vary.
136 		 */
137 		out->val[out->wlen] = carry;
138 		out->wlen = (u8)(out->wlen + carry);
139 	}
140 
141 err:
142 	return ret;
143 }
144 
145 /*
146  * Unconditionally adds 'in2' to 'in1', storing the result in "out",
147  * including the potential carry overflowing past the maximal length of
148  * 'in1' and 'in2'. The function returns 0 on success, -1 on error.
149  *
150  * Note that the length of the output depends the lengths of the inputs,
151  * but also on their values.
152  * It is the user responsibility to use this function carefully when
153  * constant time of an algorithm using this function is seeked.
154  *
155  * See "_nn_cnd_add" documentation for further details.
156  *
157  */
nn_add(nn_t out,nn_src_t in1,nn_src_t in2)158 int nn_add(nn_t out, nn_src_t in1, nn_src_t in2)
159 {
160 	return nn_cnd_add(1, out, in1, in2);
161 }
162 
163 /*
164  * Compute out = in1 + w where 'in1' is an initialized nn and 'w' a word. It is
165  * caller responsibility to ensure that the result will fit in a nn (This is
166  * for instance guaranteed if 'in1' wlen is less than NN_MAX_WORD_LEN). The
167  * function returns 0 on succes, -1 on error.
168  *
169  * The result is stored in 'out' parameter. 'out' is initialized if needed (i.e.
170  * in case aliasing is not used) and is not normalized on return.
171  *
172  * Note that the length of the output depends the lengths of the inputs,
173  * but also on their values.
174  * It is the user responsibility to use this function carefully when
175  * constant time of an algorithm using this function is seeked.
176  *
177  * This function is for internal use only.
178  */
nn_add_word(nn_t out,nn_src_t in1,word_t w)179 ATTRIBUTE_WARN_UNUSED_RET static int nn_add_word(nn_t out, nn_src_t in1, word_t w)
180 {
181 	word_t carry, tmp;
182 	u8 i, n_wlen;
183 	int ret;
184 
185 	ret = nn_check_initialized(in1); EG(ret, err);
186 
187 	/* Handle aliasing */
188 	n_wlen = in1->wlen;
189 	if (out != in1) {
190 		ret = nn_init(out, (u16)(n_wlen * WORD_BYTES)); EG(ret, err);
191 	} else {
192 		ret = nn_set_wlen(out, n_wlen); EG(ret, err);
193 	}
194 
195 	/* No matter its value, propagate the carry. */
196 	carry = w;
197 	for (i = 0; i < n_wlen; i++) {
198 		tmp = (word_t)(in1->val[i] + carry);
199 		carry = (word_t)(tmp < in1->val[i]);
200 		out->val[i] = tmp;
201 	}
202 
203 	MUST_HAVE(((out->wlen != NN_MAX_WORD_LEN) || (!carry)), ret, err);
204 	if (out->wlen != NN_MAX_WORD_LEN) {
205 		/*
206 		 * To maintain constant time, we perform carry addition in all
207 		 * cases. If carry is 0, no change is performed in practice,
208 		 * neither to 'out' value, nor to its length.
209 		 * Note that the length of the output can vary and make
210 		 * the time taken by further operations on it will vary.
211 		 */
212 		out->val[out->wlen] = carry;
213 		out->wlen = (u8)(out->wlen + carry);
214 	}
215 
216 err:
217 	return ret;
218 }
219 
220 /*
221  * Compute out = in1 + 1. Aliasing is supported i.e. nn_inc(in1, in1) works as
222  * expected and provides in1++. It is caller responsibility to ensure that the
223  * result will fit in a nn (This is for instance guaranteed if 'in1' wlen is
224  * less than NN_MAX_WORD_LEN). The function returns 0 on success, -1 on error.
225  *
226  * Note that the length of the output depends the lengths of the inputs,
227  * but also on their values.
228  * It is the user responsibility to use this function carefully when
229  * constant time of an algorithm using this function is seeked.
230  */
nn_inc(nn_t out,nn_src_t in1)231 int nn_inc(nn_t out, nn_src_t in1)
232 {
233 	return nn_add_word(out, in1, WORD(1));
234 }
235 
236 /*
237  * Conditionally subtracts 'in2' from 'in1' according to "cnd",
238  * storing the result in "out":
239  *  o out = in1 - in2 if cnd is not zero.
240  *  o out = in1 if cnd is zero.
241  *
242  * 'in1' and 'in2' must point to initialized nn, such that the value of 'in1'
243  * is larger than 'in2'. Aliasing is supported, i.e. 'out' can point to the
244  * same nn as 'in1' or 'in2'. If aliasing is not used, 'out' is initialized by
245  * the function. The length of 'out' is set to the length of 'in1'
246  * and is not normalized on return.
247  *
248  * The function returns 0 on success, -1 on error.
249  */
nn_cnd_sub(int cnd,nn_t out,nn_src_t in1,nn_src_t in2)250 int nn_cnd_sub(int cnd, nn_t out, nn_src_t in1, nn_src_t in2)
251 {
252 	word_t tmp, borrow1, borrow2, borrow = WORD(0);
253 	word_t mask = WORD_MASK_IFNOTZERO(cnd);
254 	u8 loop_wlen, i;
255 	int ret;
256 
257 	ret = nn_check_initialized(in1); EG(ret, err);
258 	ret = nn_check_initialized(in2); EG(ret, err);
259 
260 	/* Handle aliasing */
261 	loop_wlen = LOCAL_MAX(in1->wlen, in2->wlen);
262 	if ((out != in1) && (out != in2)) {
263 		ret = nn_init(out, (u16)(loop_wlen * WORD_BYTES)); EG(ret, err);
264 	} else {
265 		ret = nn_set_wlen(out, in1->wlen); EG(ret, err);
266 	}
267 
268 	/* Perform subtraction one word at a time, propagating the borrow. */
269 	for (i = 0; i < loop_wlen; i++) {
270 		tmp = (word_t)(in1->val[i] - (in2->val[i] & mask));
271 		borrow1 = (word_t)(tmp > in1->val[i]);
272 		out->val[i] = (word_t)(tmp - borrow);
273 		borrow2 = (word_t)(out->val[i] > tmp);
274 		/* There is at most one borrow going out. */
275 		borrow = (word_t)(borrow1 | borrow2);
276 	}
277 
278 	/* We only support the in1 >= in2 case */
279 	ret = (borrow != WORD(0)) ? -1 : 0;
280 
281 err:
282 	return ret;
283 }
284 
285 /* Same as the one above, but the subtraction is performed unconditionally. */
nn_sub(nn_t out,nn_src_t in1,nn_src_t in2)286 int nn_sub(nn_t out, nn_src_t in1, nn_src_t in2)
287 {
288 	return nn_cnd_sub(1, out, in1, in2);
289 }
290 
291 /*
292  * Compute out = in1 - 1 where in1 is a *positive* integer. Aliasing is
293  * supported i.e. nn_dec(A, A) works as expected and provides A -= 1.
294  * The function returns 0 on success, -1 on error.
295  */
nn_dec(nn_t out,nn_src_t in1)296 int nn_dec(nn_t out, nn_src_t in1)
297 {
298 	const word_t w = WORD(1);
299 	word_t tmp, borrow;
300 	u8 n_wlen, i;
301 	int ret;
302 
303 	ret = nn_check_initialized(in1); EG(ret, err);
304 	n_wlen = in1->wlen;
305 	ret = nn_set_wlen(out, n_wlen); EG(ret, err);
306 
307 	/* Perform subtraction w/ provided word and propagate the borrow */
308 	borrow = w;
309 	for (i = 0; i < n_wlen; i++) {
310 		tmp = (word_t)(in1->val[i] - borrow);
311 		borrow = (word_t)(tmp > in1->val[i]);
312 		out->val[i] = tmp;
313 	}
314 
315 	ret = (borrow != WORD(0)) ? -1 : 0;
316 
317 err:
318 	return ret;
319 }
320 
321 /*
322  * The following functions handle modular arithmetic. Our outputs sizes do not
323  * need a "normalization" since everything will be bounded by the modular number
324  * size.
325  *
326  * Warning: the following functions are only useful when the inputs are < p,
327  * i.e. we suppose that the input are already reduced modulo p. These primitives
328  * are mostly useful for the Fp layer. Even though they give results when
329  * applied to inputs >= p, there is no guarantee that the result is indeed < p
330  * or correct whatsoever.
331  */
332 
333 /*
334  * Compute out = in1 + in2 mod p. The function returns 0 on success, -1 on
335  * error.
336  *
337  * Aliasing not fully supported, for internal use only.
338  */
_nn_mod_add(nn_t out,nn_src_t in1,nn_src_t in2,nn_src_t p)339 static int _nn_mod_add(nn_t out, nn_src_t in1, nn_src_t in2, nn_src_t p)
340 {
341 	int ret, larger, cmp;
342 
343 	ret = nn_check_initialized(in1); EG(ret, err);
344 	ret = nn_check_initialized(in2); EG(ret, err);
345 	ret = nn_check_initialized(p); EG(ret, err);
346 	MUST_HAVE((p->wlen < NN_MAX_WORD_LEN), ret, err); /* otherwise carry could overflow */
347 	SHOULD_HAVE((!nn_cmp(in1, p, &cmp)) && (cmp < 0), ret, err); /* a SHOULD_HAVE as documented above */
348 	SHOULD_HAVE((!nn_cmp(in2, p, &cmp)) && (cmp < 0), ret, err); /* a SHOULD_HAVE as documented above */
349 
350 	ret = nn_add(out, in1, in2); EG(ret, err);
351 	/*
352 	 * If previous addition extends out->wlen, this may have an effect on
353 	 * computation time of functions below. For that reason, we always
354 	 * normalize out->wlen to p->wlen + 1. Its length is set to that of
355 	 * p after the computations.
356 	 *
357 	 * We could also use _nn_cnd_add to catch the carry and deal
358 	 * with p's of size NN_MAX_WORD_LEN.
359 	 * It is still painful because we have no constraint on the lengths
360 	 * of in1 and in2 so getting a carry out does not necessarily mean
361 	 * that the sum is larger than p...
362 	 */
363 	ret = nn_set_wlen(out, (u8)(p->wlen + 1)); EG(ret, err);
364 	ret = nn_cmp(out, p, &cmp); EG(ret, err);
365 	larger = (cmp >= 0);
366 	ret = nn_cnd_sub(larger, out, out, p); EG(ret, err);
367 	ret = nn_set_wlen(out, p->wlen);
368 
369 err:
370 	return ret;
371 }
372 
373 /*
374  * Compute out = in1 + in2 mod p. The function returns 0 on success, -1 on
375  * error.
376  *
377  * Aliasing is supported.
378  */
nn_mod_add(nn_t out,nn_src_t in1,nn_src_t in2,nn_src_t p)379 int nn_mod_add(nn_t out, nn_src_t in1, nn_src_t in2, nn_src_t p)
380 {
381 	int ret;
382 
383 	if(out == p){
384 		nn p_cpy;
385 		p_cpy.magic = WORD(0);
386 
387 		ret = nn_copy(&p_cpy, p); EG(ret, err1);
388 		ret = _nn_mod_add(out, in1, in2, &p_cpy);
389 
390 err1:
391 		nn_uninit(&p_cpy);
392 		EG(ret, err);
393 	}
394 	else{
395 		ret = _nn_mod_add(out, in1, in2, p);
396 	}
397 
398 err:
399 	return ret;
400 }
401 
402 /*
403  * Compute out = in1 + 1 mod p. The function returns 0 on success, -1 on error.
404  *
405  * Aliasing not fully supported, for internal use only.
406  */
_nn_mod_inc(nn_t out,nn_src_t in1,nn_src_t p)407 static int _nn_mod_inc(nn_t out, nn_src_t in1, nn_src_t p)
408 {
409 	int larger, ret, cmp;
410 
411 	ret = nn_check_initialized(in1); EG(ret, err);
412 	ret = nn_check_initialized(p); EG(ret, err);
413 	MUST_HAVE((p->wlen < NN_MAX_WORD_LEN), ret, err); /* otherwise carry could overflow */
414 	SHOULD_HAVE((!nn_cmp(in1, p, &cmp)) && (cmp < 0), ret, err); /* a SHOULD_HAVE as documented above */
415 
416 	ret = nn_inc(out, in1); EG(ret, err);
417 	ret = nn_set_wlen(out, (u8)(p->wlen + 1)); EG(ret, err); /* see comment in nn_mod_add() */
418 	ret = nn_cmp(out, p, &cmp); EG(ret, err);
419 	larger = (cmp >= 0);
420 	ret = nn_cnd_sub(larger, out, out, p); EG(ret, err);
421 	ret = nn_set_wlen(out, p->wlen);
422 
423 err:
424 	return ret;
425 }
426 
427 /*
428  * Compute out = in1 + 1 mod p. The function returns 0 on success, -1 on error.
429  *
430  * Aliasing supported.
431  */
nn_mod_inc(nn_t out,nn_src_t in1,nn_src_t p)432 int nn_mod_inc(nn_t out, nn_src_t in1, nn_src_t p)
433 {
434 	int ret;
435 
436 	if(out == p){
437 		nn p_cpy;
438 		p_cpy.magic = WORD(0);
439 
440 		ret = nn_copy(&p_cpy, p); EG(ret, err1);
441 		ret = _nn_mod_inc(out, in1, &p_cpy);
442 
443 err1:
444 		nn_uninit(&p_cpy);
445 		EG(ret, err);
446 	}
447 	else{
448 		ret = _nn_mod_inc(out, in1, p);
449 	}
450 
451 err:
452 	return ret;
453 
454 }
455 
456 /*
457  * Compute out = in1 - in2 mod p. The function returns 0 on success, -1 on
458  * error.
459  *
460  * Aliasing not supported, for internal use only.
461  */
_nn_mod_sub(nn_t out,nn_src_t in1,nn_src_t in2,nn_src_t p)462 static int _nn_mod_sub(nn_t out, nn_src_t in1, nn_src_t in2, nn_src_t p)
463 {
464 	int smaller, ret, cmp;
465 	nn_src_t in2_;
466 	nn in2_cpy;
467 	in2_cpy.magic = WORD(0);
468 
469 	ret = nn_check_initialized(in1); EG(ret, err);
470 	ret = nn_check_initialized(in2); EG(ret, err);
471 	ret = nn_check_initialized(p); EG(ret, err);
472 	MUST_HAVE((p->wlen < NN_MAX_WORD_LEN), ret, err); /* otherwise carry could overflow */
473 	SHOULD_HAVE((!nn_cmp(in1, p, &cmp)) && (cmp < 0), ret, err); /* a SHOULD_HAVE as documented above */
474 	SHOULD_HAVE((!nn_cmp(in2, p, &cmp)) && (cmp < 0), ret, err); /* a SHOULD_HAVE as documented above */
475 
476 	/* Handle the case where in2 and out are aliased */
477 	if (in2 == out) {
478 		ret = nn_copy(&in2_cpy, in2); EG(ret, err);
479 		in2_ = &in2_cpy;
480 	} else {
481 		ret = nn_init(&in2_cpy, 0); EG(ret, err);
482 		in2_ = in2;
483 	}
484 
485 	/* The below trick is used to avoid handling of "negative" numbers. */
486 	ret = nn_cmp(in1, in2_, &cmp); EG(ret, err);
487 	smaller = (cmp < 0);
488 	ret = nn_cnd_add(smaller, out, in1, p); EG(ret, err);
489 	ret = nn_set_wlen(out, (u8)(p->wlen + 1)); EG(ret, err);/* See Comment in nn_mod_add() */
490 	ret = nn_sub(out, out, in2_); EG(ret, err);
491 	ret = nn_set_wlen(out, p->wlen);
492 
493 err:
494 	nn_uninit(&in2_cpy);
495 
496 	return ret;
497 }
498 
499 /*
500  * Compute out = in1 - in2 mod p. The function returns 0 on success, -1 on
501  * error.
502  *
503  * Aliasing supported.
504  */
nn_mod_sub(nn_t out,nn_src_t in1,nn_src_t in2,nn_src_t p)505 int nn_mod_sub(nn_t out, nn_src_t in1, nn_src_t in2, nn_src_t p)
506 {
507 	int ret;
508 
509 	if(out == p){
510 		nn p_cpy;
511 		p_cpy.magic = WORD(0);
512 
513 		ret = nn_copy(&p_cpy, p); EG(ret, err1);
514 		ret = _nn_mod_sub(out, in1, in2, &p_cpy);
515 
516 err1:
517 		nn_uninit(&p_cpy);
518 		EG(ret, err);
519 	}
520 	else{
521 		ret = _nn_mod_sub(out, in1, in2, p);
522 	}
523 
524 err:
525 	return ret;
526 }
527 
528 /*
529  * Compute out = in1 - 1 mod p. The function returns 0 on success, -1 on error
530  *
531  * Aliasing not supported, for internal use only.
532  */
_nn_mod_dec(nn_t out,nn_src_t in1,nn_src_t p)533 static int _nn_mod_dec(nn_t out, nn_src_t in1, nn_src_t p)
534 {
535 	int ret, iszero, cmp;
536 
537 	ret = nn_check_initialized(in1); EG(ret, err);
538 	ret = nn_check_initialized(p); EG(ret, err);
539 	MUST_HAVE((p->wlen < NN_MAX_WORD_LEN), ret, err); /* otherwise carry could overflow */
540 	FORCE_USED_VAR(cmp); /* nop to silence possible warning with macro below */
541 	SHOULD_HAVE((!nn_cmp(in1, p, &cmp)) && (cmp < 0), ret, err);  /* a SHOULD_HAVE; Documented above */
542 
543 	/* The below trick is used to avoid handling of "negative" numbers. */
544 	ret = nn_iszero(in1, &iszero); EG(ret, err);
545 	ret = nn_cnd_add(iszero, out, in1, p); EG(ret, err);
546 	ret = nn_set_wlen(out, (u8)(p->wlen + 1)); EG(ret, err); /* See Comment in nn_mod_add() */
547 	ret = nn_dec(out, out); EG(ret, err);
548 	ret = nn_set_wlen(out, p->wlen);
549 
550 err:
551 	return ret;
552 }
553 
554 /*
555  * Compute out = in1 - 1 mod p. The function returns 0 on success, -1 on error
556  *
557  * Aliasing supported.
558  */
nn_mod_dec(nn_t out,nn_src_t in1,nn_src_t p)559 int nn_mod_dec(nn_t out, nn_src_t in1, nn_src_t p)
560 {
561 	int ret;
562 
563 	if(out == p){
564 		nn p_cpy;
565 		p_cpy.magic = WORD(0);
566 
567 		ret = nn_copy(&p_cpy, p); EG(ret, err1);
568 		ret = _nn_mod_dec(out, in1, &p_cpy);
569 
570 err1:
571 		nn_uninit(&p_cpy);
572 		EG(ret, err);
573 	}
574 	else{
575 		ret = _nn_mod_dec(out, in1, p);
576 	}
577 
578 err:
579 	return ret;
580 }
581 
582 /*
583  * Compute out = -in mod p. The function returns 0 on success, -1 on error.
584  * Because we only support positive integers, we compute
585  * out = p - in (except when value is 0).
586  *
587  * We suppose that in is already reduced modulo p.
588  *
589  * Aliasing is supported.
590  *
591  */
nn_mod_neg(nn_t out,nn_src_t in,nn_src_t p)592 int nn_mod_neg(nn_t out, nn_src_t in, nn_src_t p)
593 {
594 	int ret, cmp, iszero;
595 
596 	FORCE_USED_VAR(cmp);
597 
598 	ret = nn_check_initialized(in); EG(ret, err);
599 	ret = nn_check_initialized(p); EG(ret, err);
600 
601 	SHOULD_HAVE((!nn_cmp(in, p, &cmp)) && (cmp < 0), ret, err);  /* a SHOULD_HAVE; Documented above */
602 
603 	ret = nn_iszero(in, &iszero); EG(ret, err);
604 	if (iszero) {
605 		ret = nn_init(out, 0); EG(ret, err);
606 		ret = nn_zero(out); EG(ret, err);
607 	} else {
608 		ret = nn_sub(out, p, in); EG(ret, err);
609 	}
610 
611 err:
612 	return ret;
613 }
614