BitwiseOperations.cpp 8.4 KB

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