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