Получить по модулю из двух целочисленных массивов 4x64 бит

Я использую OpenCL для программирования GPGPU, но, к сожалению, нет встроенной поддержки 256-битных целых чисел. Я решил разделить 256-битное целое число на четыре 64-битных целых числа. Довольно хорошее решение для базовых операций, но как я могу получить их по модулю?

Мне нужно сделать это:

(uint256) % (uint256)

Но с OpenCL у меня может быть только это:

[ (uint64), (uint64), (uint64), (uint64) ] % [ (uint64), (uint64), (uint64), (uint64) ]

Итак, как я могу этого добиться? Какой алгоритм мне использовать, и самое главное — какой проще всего реализовать?

P.S. Мне это нужно для криптографии с открытым ключом.

EDIT: у меня не реализовано ни сложение, ни вычитание.


person Alex S.    schedule 06.06.2020    source источник
comment
Спасибо! Есть ли у вас рекомендуемые чтения?   -  person Alex S.    schedule 06.06.2020
comment
Ты можешь делать то, что хочешь, карандашом? Найдите резинового утёнка... говорите медленно... Рассматривали ли вы некоторые из расширенных библиотек точности? Итак... похоже, вы еще ничего не пробовали. Просмотрите минимально воспроизводимый пример.   -  person 2785528    schedule 06.06.2020
comment
Я пробовал искать в гугле, но ничего не нашел. OpenCL не похож на C/C++, и нет таких библиотек, как gmp и другие.   -  person Alex S.    schedule 06.06.2020
comment
У меня не реализовано ни сложение, ни вычитание. --› Вам нужна помощь с дополнением?   -  person chux - Reinstate Monica    schedule 07.06.2020
comment
Со сложением вычитанием. Я был бы очень признателен.   -  person Alex S.    schedule 07.06.2020
comment
Попробуйте GNU Multiprecision gmp-библиотеку, в которой уже реализовано все, что вам нужно, и которая является основой кода многих криптографических библиотек. .   -  person Luis Colorado    schedule 08.06.2020
comment
Я использую OpenCL C, и в библиотеках нет такого смысла. Конечно, я бы использовал его, если бы работал с C/C++.   -  person Alex S.    schedule 08.06.2020


Ответы (1)


Вот простой (и довольно эффективный) алгоритм, который вычисляет a % b, используя только вычитание, умножение на 2, деление на 2 и сравнение (все это легко реализовать для вашего uint256).

uint256 modulo(uint256 a, uint256 b) {
  int i = 0;
  while (b <= a) {
    b = b * 2; // watch out for overflow!
    i++;
  }
  while (i--) {
    b = b / 2;
    if (b <= a) {
      a = a - b;
    }
  }
  return a;
}

Вот пример:

start: a = 40, b = 7
i = 1, a = 40, b = 14
i = 2, a = 40, b = 28
i = 3, a = 40, b = 56

i = 3, b = 28, a = 40 - 28 = 12
i = 2, b = 14, a = 12 (b > a so nothing happens)
i = 1, b = 7, a = 12 - 7 = 5
i = 0, so we stop and return a = 5

РЕДАКТИРОВАТЬ: Почему это работает? Наивный способ вычисления остатка по модулю, если следующее:

int modulo(int a, int b) {
  while (a >= b) {
    a -= b;
  }
  return a;
}

Предлагаемое решение использует ту же идею, но более эффективным способом. Мы знаем, что в итоге мы вычтем b из a ровно k раз. Мы не знаем значение k. k может быть представлено в двоичном виде как 2^0 * k_0 + 2^1 * k_1 + 2^2 * k_2 + .... Алгоритм исходит из самых больших значений 2^i и пытается вычесть 2^i * b. Благодаря этому мы достигаем логарифмической временной сложности вместо линейной.

Отказ от ответственности: я бы не стал использовать эту реализацию как настоящую криптографическую реализацию, поскольку она подвержена атакам по сторонним каналам (разное время выполнения в зависимости от ввода).

person Igor    schedule 06.06.2020
comment
Ну, я спросил, как реализовать по модулю для двух целочисленных массивов 4x64 бит, а не для двух uint256. Дело в том, что я могу работать только с 64-битными целыми числами. - person Alex S.; 06.06.2020
comment
@AlexanderSadovskyi Вы упомянули, что довольно хорошее решение для базовых операций, поэтому я предположил, что у вас уже реализованы базовые операции, такие как вычитание. Приведенный выше алгоритм работает для любой целочисленной реализации, если вы можете выполнить 4 операции, упомянутые в начале. Просто замените, например. b = b * 2 с вашей реализацией умножения uint256 на 2 (что легко) и т. д. - person Igor; 06.06.2020
comment
Я имел в виду базовые побитовые операции. У меня ничего не реализовано, так как мне нужно только получить по модулю. - person Alex S.; 07.06.2020
comment
Не могли бы вы добавить способ подумать о том, почему это работает? - person גלעד ברקן; 07.06.2020
comment
@גלעדברקן Добавлено объяснение - person Igor; 08.06.2020