BitwiseOperations.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
  3. * Copyright (c) 2020-2021, Dex♪ <dexes.ttp@gmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include "UnsignedBigIntegerAlgorithms.h"
  8. #include <AK/BuiltinWrappers.h>
  9. #include <AK/NumericLimits.h>
  10. namespace Crypto {
  11. /**
  12. * Complexity: O(N) where N is the number of words in the shorter value
  13. * Method:
  14. * Apply <op> word-wise until words in the shorter value are used up
  15. * then copy the rest of the words verbatim from the longer value.
  16. */
  17. FLATTEN void UnsignedBigIntegerAlgorithms::bitwise_or_without_allocation(
  18. UnsignedBigInteger const& left,
  19. UnsignedBigInteger const& right,
  20. UnsignedBigInteger& output)
  21. {
  22. // If either of the BigInts are invalid, the output is just the other one.
  23. if (left.is_invalid()) {
  24. output.set_to(right);
  25. return;
  26. }
  27. if (right.is_invalid()) {
  28. output.set_to(left);
  29. return;
  30. }
  31. UnsignedBigInteger const *shorter, *longer;
  32. if (left.length() < right.length()) {
  33. shorter = &left;
  34. longer = &right;
  35. } else {
  36. shorter = &right;
  37. longer = &left;
  38. }
  39. output.m_words.resize_and_keep_capacity(longer->length());
  40. size_t longer_offset = longer->length() - shorter->length();
  41. for (size_t i = 0; i < shorter->length(); ++i)
  42. output.m_words[i] = longer->words()[i] | shorter->words()[i];
  43. __builtin_memcpy(output.m_words.data() + shorter->length(), longer->words().data() + shorter->length(), sizeof(u32) * longer_offset);
  44. }
  45. /**
  46. * Complexity: O(N) where N is the number of words in the shorter value
  47. * Method:
  48. * Apply 'and' word-wise until words in the shorter value are used up
  49. * and zero the rest.
  50. */
  51. FLATTEN void UnsignedBigIntegerAlgorithms::bitwise_and_without_allocation(
  52. UnsignedBigInteger const& left,
  53. UnsignedBigInteger const& right,
  54. UnsignedBigInteger& output)
  55. {
  56. // If either of the BigInts are invalid, the output is just the other one.
  57. if (left.is_invalid()) {
  58. output.set_to(right);
  59. return;
  60. }
  61. if (right.is_invalid()) {
  62. output.set_to(left);
  63. return;
  64. }
  65. UnsignedBigInteger const *shorter, *longer;
  66. if (left.length() < right.length()) {
  67. shorter = &left;
  68. longer = &right;
  69. } else {
  70. shorter = &right;
  71. longer = &left;
  72. }
  73. output.m_words.resize_and_keep_capacity(longer->length());
  74. size_t longer_offset = longer->length() - shorter->length();
  75. for (size_t i = 0; i < shorter->length(); ++i)
  76. output.m_words[i] = longer->words()[i] & shorter->words()[i];
  77. __builtin_memset(output.m_words.data() + shorter->length(), 0, sizeof(u32) * longer_offset);
  78. }
  79. /**
  80. * Complexity: O(N) where N is the number of words in the shorter value
  81. * Method:
  82. * Apply 'xor' word-wise until words in the shorter value are used up
  83. * and copy the rest.
  84. */
  85. FLATTEN void UnsignedBigIntegerAlgorithms::bitwise_xor_without_allocation(
  86. UnsignedBigInteger const& left,
  87. UnsignedBigInteger const& right,
  88. UnsignedBigInteger& output)
  89. {
  90. // If either of the BigInts are invalid, the output is just the other one.
  91. if (left.is_invalid()) {
  92. output.set_to(right);
  93. return;
  94. }
  95. if (right.is_invalid()) {
  96. output.set_to(left);
  97. return;
  98. }
  99. UnsignedBigInteger const *shorter, *longer;
  100. if (left.length() < right.length()) {
  101. shorter = &left;
  102. longer = &right;
  103. } else {
  104. shorter = &right;
  105. longer = &left;
  106. }
  107. output.m_words.resize_and_keep_capacity(longer->length());
  108. size_t longer_offset = longer->length() - shorter->length();
  109. for (size_t i = 0; i < shorter->length(); ++i)
  110. output.m_words[i] = longer->words()[i] ^ shorter->words()[i];
  111. __builtin_memcpy(output.m_words.data() + shorter->length(), longer->words().data() + shorter->length(), sizeof(u32) * longer_offset);
  112. }
  113. /**
  114. * Complexity: O(N) where N is the number of words
  115. */
  116. FLATTEN void UnsignedBigIntegerAlgorithms::bitwise_not_fill_to_one_based_index_without_allocation(
  117. UnsignedBigInteger const& right,
  118. size_t index,
  119. UnsignedBigInteger& output)
  120. {
  121. // If the value is invalid, the output value is invalid as well.
  122. if (right.is_invalid()) {
  123. output.invalidate();
  124. return;
  125. }
  126. if (index == 0) {
  127. output.set_to_0();
  128. return;
  129. }
  130. size_t size = (index + UnsignedBigInteger::BITS_IN_WORD - 1) / UnsignedBigInteger::BITS_IN_WORD;
  131. output.m_words.resize_and_keep_capacity(size);
  132. VERIFY(size > 0);
  133. for (size_t i = 0; i < size - 1; ++i)
  134. output.m_words[i] = ~(i < right.length() ? right.words()[i] : 0);
  135. index -= (size - 1) * UnsignedBigInteger::BITS_IN_WORD;
  136. auto last_word_index = size - 1;
  137. auto last_word = last_word_index < right.length() ? right.words()[last_word_index] : 0;
  138. output.m_words[last_word_index] = (NumericLimits<UnsignedBigInteger::Word>::max() >> (UnsignedBigInteger::BITS_IN_WORD - index)) & ~last_word;
  139. }
  140. /**
  141. * Complexity : O(N + num_bits % 8) where N is the number of words in the number
  142. * Shift method :
  143. * Start by shifting by whole words in num_bits (by putting missing words at the start),
  144. * then shift the number's words two by two by the remaining amount of bits.
  145. */
  146. FLATTEN void UnsignedBigIntegerAlgorithms::shift_left_without_allocation(
  147. UnsignedBigInteger const& number,
  148. size_t num_bits,
  149. UnsignedBigInteger& temp_result,
  150. UnsignedBigInteger& temp_plus,
  151. UnsignedBigInteger& output)
  152. {
  153. // We can only do shift operations on individual words
  154. // where the shift amount is <= size of word (32).
  155. // But we do know how to shift by a multiple of word size (e.g 64=32*2)
  156. // So we first shift the result by how many whole words fit in 'num_bits'
  157. shift_left_by_n_words(number, num_bits / UnsignedBigInteger::BITS_IN_WORD, temp_result);
  158. output.set_to(temp_result);
  159. // And now we shift by the leftover amount of bits
  160. num_bits %= UnsignedBigInteger::BITS_IN_WORD;
  161. if (num_bits == 0) {
  162. return;
  163. }
  164. for (size_t i = 0; i < temp_result.length(); ++i) {
  165. u32 current_word_of_temp_result = shift_left_get_one_word(temp_result, num_bits, i);
  166. output.m_words[i] = current_word_of_temp_result;
  167. }
  168. // Shifting the last word can produce a carry
  169. u32 carry_word = shift_left_get_one_word(temp_result, num_bits, temp_result.length());
  170. if (carry_word != 0) {
  171. // output += (carry_word << temp_result.length())
  172. // FIXME : Using temp_plus this way to transform carry_word into a bigint is not
  173. // efficient nor pretty. Maybe we should have an "add_with_shift" method ?
  174. temp_plus.set_to_0();
  175. temp_plus.m_words.append(carry_word);
  176. shift_left_by_n_words(temp_plus, temp_result.length(), temp_result);
  177. add_into_accumulator_without_allocation(output, temp_result);
  178. }
  179. }
  180. void UnsignedBigIntegerAlgorithms::shift_left_by_n_words(
  181. UnsignedBigInteger const& number,
  182. size_t number_of_words,
  183. UnsignedBigInteger& output)
  184. {
  185. // shifting left by N words means just inserting N zeroes to the beginning of the words vector
  186. output.set_to_0();
  187. output.m_words.resize_and_keep_capacity(number_of_words + number.length());
  188. __builtin_memset(output.m_words.data(), 0, number_of_words * sizeof(unsigned));
  189. __builtin_memcpy(&output.m_words.data()[number_of_words], number.m_words.data(), number.m_words.size() * sizeof(unsigned));
  190. }
  191. void UnsignedBigIntegerAlgorithms::shift_right_by_n_words(
  192. UnsignedBigInteger const& number,
  193. size_t number_of_words,
  194. UnsignedBigInteger& output)
  195. {
  196. // shifting right by N words means just not copying the first words
  197. output.set_to_0();
  198. output.m_words.resize_and_keep_capacity(number.length() - number_of_words);
  199. __builtin_memcpy(output.m_words.data(), &number.m_words.data()[number_of_words], (number.m_words.size() - number_of_words) * sizeof(unsigned));
  200. }
  201. /**
  202. * Returns the word at a requested index in the result of a shift operation
  203. */
  204. ALWAYS_INLINE UnsignedBigInteger::Word UnsignedBigIntegerAlgorithms::shift_left_get_one_word(
  205. UnsignedBigInteger const& number,
  206. size_t num_bits,
  207. size_t result_word_index)
  208. {
  209. // "<= length()" (rather than length() - 1) is intentional,
  210. // The result index of length() is used when calculating the carry word
  211. VERIFY(result_word_index <= number.length());
  212. VERIFY(num_bits <= UnsignedBigInteger::BITS_IN_WORD);
  213. u32 result = 0;
  214. // we need to check for "num_bits != 0" since shifting right by 32 is apparently undefined behavior!
  215. if (result_word_index > 0 && num_bits != 0) {
  216. result += number.m_words[result_word_index - 1] >> (UnsignedBigInteger::BITS_IN_WORD - num_bits);
  217. }
  218. if (result_word_index < number.length() && num_bits < 32) {
  219. result += number.m_words[result_word_index] << num_bits;
  220. }
  221. return result;
  222. }
  223. }