bn_add.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the OpenSSL license (the "License"). You may not use
  5. * this file except in compliance with the License. You can obtain a copy
  6. * in the file LICENSE in the source distribution or at
  7. * https://www.openssl.org/source/license.html
  8. */
  9. #include "internal/cryptlib.h"
  10. #include "bn_lcl.h"
  11. /* r can == a or b */
  12. int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
  13. {
  14. int a_neg = a->neg, ret;
  15. bn_check_top(a);
  16. bn_check_top(b);
  17. /*-
  18. * a + b a+b
  19. * a + -b a-b
  20. * -a + b b-a
  21. * -a + -b -(a+b)
  22. */
  23. if (a_neg ^ b->neg) {
  24. /* only one is negative */
  25. if (a_neg) {
  26. const BIGNUM *tmp;
  27. tmp = a;
  28. a = b;
  29. b = tmp;
  30. }
  31. /* we are now a - b */
  32. if (BN_ucmp(a, b) < 0) {
  33. if (!BN_usub(r, b, a))
  34. return 0;
  35. r->neg = 1;
  36. } else {
  37. if (!BN_usub(r, a, b))
  38. return 0;
  39. r->neg = 0;
  40. }
  41. return 1;
  42. }
  43. ret = BN_uadd(r, a, b);
  44. r->neg = a_neg;
  45. bn_check_top(r);
  46. return ret;
  47. }
  48. /* unsigned add of b to a */
  49. int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
  50. {
  51. int max, min, dif;
  52. const BN_ULONG *ap, *bp;
  53. BN_ULONG *rp, carry, t1, t2;
  54. bn_check_top(a);
  55. bn_check_top(b);
  56. if (a->top < b->top) {
  57. const BIGNUM *tmp;
  58. tmp = a;
  59. a = b;
  60. b = tmp;
  61. }
  62. max = a->top;
  63. min = b->top;
  64. dif = max - min;
  65. if (bn_wexpand(r, max + 1) == NULL)
  66. return 0;
  67. r->top = max;
  68. ap = a->d;
  69. bp = b->d;
  70. rp = r->d;
  71. carry = bn_add_words(rp, ap, bp, min);
  72. rp += min;
  73. ap += min;
  74. while (dif) {
  75. dif--;
  76. t1 = *(ap++);
  77. t2 = (t1 + carry) & BN_MASK2;
  78. *(rp++) = t2;
  79. carry &= (t2 == 0);
  80. }
  81. *rp = carry;
  82. r->top += carry;
  83. r->neg = 0;
  84. bn_check_top(r);
  85. return 1;
  86. }
  87. /* unsigned subtraction of b from a, a must be larger than b. */
  88. int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
  89. {
  90. int max, min, dif;
  91. BN_ULONG t1, t2, borrow, *rp;
  92. const BN_ULONG *ap, *bp;
  93. bn_check_top(a);
  94. bn_check_top(b);
  95. max = a->top;
  96. min = b->top;
  97. dif = max - min;
  98. if (dif < 0) { /* hmm... should not be happening */
  99. BNerr(BN_F_BN_USUB, BN_R_ARG2_LT_ARG3);
  100. return 0;
  101. }
  102. if (bn_wexpand(r, max) == NULL)
  103. return 0;
  104. ap = a->d;
  105. bp = b->d;
  106. rp = r->d;
  107. borrow = bn_sub_words(rp, ap, bp, min);
  108. ap += min;
  109. rp += min;
  110. while (dif) {
  111. dif--;
  112. t1 = *(ap++);
  113. t2 = (t1 - borrow) & BN_MASK2;
  114. *(rp++) = t2;
  115. borrow &= (t1 == 0);
  116. }
  117. r->top = max;
  118. r->neg = 0;
  119. bn_correct_top(r);
  120. return 1;
  121. }
  122. int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
  123. {
  124. int max;
  125. int add = 0, neg = 0;
  126. bn_check_top(a);
  127. bn_check_top(b);
  128. /*-
  129. * a - b a-b
  130. * a - -b a+b
  131. * -a - b -(a+b)
  132. * -a - -b b-a
  133. */
  134. if (a->neg) {
  135. if (b->neg) {
  136. const BIGNUM *tmp;
  137. tmp = a;
  138. a = b;
  139. b = tmp;
  140. } else {
  141. add = 1;
  142. neg = 1;
  143. }
  144. } else {
  145. if (b->neg) {
  146. add = 1;
  147. neg = 0;
  148. }
  149. }
  150. if (add) {
  151. if (!BN_uadd(r, a, b))
  152. return 0;
  153. r->neg = neg;
  154. return 1;
  155. }
  156. /* We are actually doing a - b :-) */
  157. max = (a->top > b->top) ? a->top : b->top;
  158. if (bn_wexpand(r, max) == NULL)
  159. return 0;
  160. if (BN_ucmp(a, b) < 0) {
  161. if (!BN_usub(r, b, a))
  162. return 0;
  163. r->neg = 1;
  164. } else {
  165. if (!BN_usub(r, a, b))
  166. return 0;
  167. r->neg = 0;
  168. }
  169. bn_check_top(r);
  170. return 1;
  171. }