Инверсия модульного умножения в коде

Я много читал об этом предмете, об алгоритме Евклида, и у меня есть все ссылки, необходимые для этого предмета, прямо здесь:

(Лучший источник для моего вопроса) -> Math Explanation

Еще один отличный пример -> Math Explanation 2

Wiki -> Расширенный евклидов

Отличный ответ для добавления значений -> Добавить операцию

Тут я совсем запутался -> АФФИННЫЕ ШИФРЫ

Однако из всех этих источников я до сих пор не понимаю, как реализовать это с помощью кода (или псевдокода) или, по крайней мере, найти способ его написать.

Итак, я напишу основы, давайте предположим, что у меня есть эта формула:

(x * key) % mod = результат
0 ‹= X ‹= mod
0 ‹= ключ ‹= mod
0 ‹= результат‹= mod

key и mod являются константами.
* означает операцию умножения
% означает операцию остатка (отредактировано для уточнения)
x и результат являются динамическими.

Я хочу создать формулу, которая даст мне x через код на Java.

Функция, которая вычисляет для меня результат:

private int MultModulus(int num, int key, int mod)
{
    return (num * key) % mod;
}

как найти Х? что я должен написать, чтобы рассчитать его? это тот момент, когда я не понял, давайте предположим, что моя сигнатура функции будет:

private int InverseMultModulus(int result, int key, int mod)
{
    x = ...
    return x;
}

person Ori Frish    schedule 29.09.2015    source источник
comment
небольшая информация. % — это оператор остатка, а не математическое представление вычисления по модулю. Вот для чего, например, Math#floorMod.   -  person SomeJavaGuy    schedule 29.09.2015
comment
о, в таком случае я поясню, что я имел в виду оператор остатка.   -  person Ori Frish    schedule 29.09.2015
comment
Проблема не четко сформулирована. Как правило, существует несколько возможных значений x. Какой ты хочешь?   -  person John Bollinger    schedule 29.09.2015
comment
Уникального ответа нет. Например. если result == 1, mod == 2 и key == 3, x может быть любым положительным нечетным числом.   -  person Paul Boddington    schedule 29.09.2015
comment
для операции добавления есть только одно решение, как для умножения есть несколько ответов? источники, которые я привел, показывают, что должен быть только 1 правильный ответ. если я правильно их понял.   -  person Ori Frish    schedule 29.09.2015
comment
Также возможно, что нет ответа.   -  person John Bollinger    schedule 29.09.2015
comment
Я снова отредактирую вопрос, 0 ‹= X ‹= мод, 0 ‹= KEY ‹= мод   -  person Ori Frish    schedule 29.09.2015
comment
(X*5)%3=1 означает, что X может быть 2, 5, 8 и т. д. (для положительных чисел). Как вы хотели, чтобы ваш ответ был предоставлен вам?   -  person ergonaut    schedule 29.09.2015
comment
Ответа вообще нет, если key делит mod и result не кратно key. В более общем случае, если key и mod не взаимно просты, то будет по крайней мере одно значение для result, которому не соответствует x. В противном случае их может быть больше одного.   -  person John Bollinger    schedule 29.09.2015
comment
Я предполагаю, что все это должно быть сделано по модулю mod. В этом случае вам нужно посмотреть на класс BigInteger. Предполагая, что result и key не имеют общих простых множителей с mod, ответ (по модулю mod) равен key.modInverse(mod).multiply(result).   -  person Paul Boddington    schedule 29.09.2015
comment
@OriFrish, ответ math.stackexchange.com, который вы представили, дает довольно четкое объяснение того, как эффективно выполнять вычисления, когда на самом деле вообще есть какой-либо ответ. В статье Википедии описывается, как вычислить необходимые количества. Что мешает вам реализовать нужный алгоритм на основе информации, предоставленной этими ресурсами?   -  person John Bollinger    schedule 29.09.2015
comment
Ну, если быть честным с вами, я сижу с ручкой и бумагой и просто не понимаю, как преобразовать это в код, я не полностью понял метод, который они использовали для создания преобразования.   -  person Ori Frish    schedule 29.09.2015
comment
@OriFrish, если вопрос сводится к тому, чтобы реализовать для меня расширенный алгоритм Евклида (или аналогичный), то это выходит за рамки SO. Если у вас есть конкретные вопросы о том, как реализовать алгоритм, мы можем ответить на них (пожалуйста, разместите отдельные вопросы). Если вы вообще не понимаете алгоритм, вы можете обнаружить, что мы готовы ответить на конкретные вопросы о нем, но большинство таких вопросов технически тоже выходит за рамки.   -  person John Bollinger    schedule 29.09.2015


Ответы (2)


Если, как описано в комментариях к ответу @ergonaut, вам нужно решить эту проблему только для относительно небольшого количества исходных значений x и относительно небольшого значения mod, то одним из разумных подходов будет создание таблицы декодирования. заранее: выполните опережающее вычисление для всех возможных x и запишите начальное x в массив, проиндексированный по result. Затем вы можете выполнить простой поиск в массиве, чтобы получить x для каждого результата. Это определенно превзойдет вычисление x отдельно для каждого значения в достаточно длинной последовательности значений (то есть символов в достаточно длинном зашифрованном сообщении). Конечно, если вы делаете это в духе шифра Виньера, то есть с многобайтовым ключом, то это умножит входную длину, необходимую для предварительного вычисления таблицы декодирования, чтобы выиграть.

Однако имейте в виду, что использование функции, которую вы описываете, для определения жизнеспособного шифра зависит от каждого действительного входного значения, дающего отличный результат. Однако, как мы уже обсуждали, некоторые комбинации key и mod дают повторяющиеся результаты. Кроме того, если пространство возможных результирующих значений имеет тот же размер, что и пространство возможных входных значений, то вы должны выбрать комбинацию key и mod, которая приведет к использованию всех возможных значений result, иначе вы не сможете избежать дублирования.

Если вы хотите шифровать байты как байты и иметь возможность обрабатывать общие файлы, то единственным возможным mod является 256. Если вы выберете меньший, то должна быть хотя бы одна пара входных байтов, которые сопоставляются с одним и тем же шифробайтом. С другой стороны, если вы выберете большее значение mod, диапазон значений результата не может быть сопоставлен 1:1 с диапазоном типа byte. Кроме того, вы должны быть уверены, что выбрали key, взаимно простые с 256, но это легко: поскольку 256 является степенью двойки, подойдет любой нечетный ключ. Пока вы выбираете такой ключ, никакие два входных значения в любом диапазоне из 256 последовательных целых чисел не будут сопоставлены с одним и тем же результатом.

person John Bollinger    schedule 29.09.2015
comment
Спасибо за ваш ответ, можете ли вы предложить какой-либо другой подход, с помощью которого я могу создать этот шифр? может быть, что-то, что не включает какую-либо операцию по модулю. Я решил это, зашифровав каждый символ до данных размером 4 байта. поэтому, когда я читаю обратно, я уверен, что мой зашифрованный файл основан на 4-байтовых данных, которые я могу прочитать, и просто расшифровать обратно. однако он делает каждый файл в 4 раза больше, что не является хорошим преобразованием. - person Ori Frish; 29.09.2015
comment
@OriFrish, можно реализовать варианты шифра Виньера для алфавитов любого размера. В частности, вы можете реализовать его для 256-символьного алфавита. Обычно это требует вычисления остатков, но это (x + key) % size, а не (x * key) % size. Расшифровать гораздо проще, зная ключ. Возможно, это подойдет для вашей цели. - person John Bollinger; 29.09.2015

Запустите MultModulus, но итерируйте с X в [0, mod], чтобы вернуть ответ и сохранить его в массиве.

for (int i=0;i<mod;i++){
    if (MultModulus(i, key, mod) == result){
       // store answer in array
    }
}

return array;
person ergonaut    schedule 29.09.2015
comment
Однако ваше решение работает, оно работает частично, так как по какой-то причине некоторые ascii-буквы, такие как и ', просто не записываются обратно, оно также работает таким же образом для решения операции добавления, которое я привел, вы знаете, почему это? - person Ori Frish; 29.09.2015
comment
@OriFrish, вы поставили числовую проблему. Какое отношение к этому имеют символы ASCII? - person John Bollinger; 29.09.2015
comment
Вы правы, в основном я пишу небольшой алгоритм преобразования для шифрования файлов, поскольку он не использует никаких реальных алгоритмов шифрования. теперь алгоритм заменяет любую букву ascii в файле ключом, который можно добавить к символу или умножить на него. и я сделал это, написав 4-байтовый (для каждого символа) зашифрованный файл, но я хочу попытаться сделать это с 1 байтом и функцией модуля, чтобы сэкономить место. - person Ori Frish; 29.09.2015
comment
Не уверен насчет ascii, но вы можете использовать этот метод везде, где вы не хотите использовать/выводить обратный расчет с помощью прямого расчета, и у вас есть небольшой конечный набор входных данных, который может быть. например. Если бы вашей формулой была a^b (mod c), и вы не хотели бы иметь дело с корнями/логарифмами, и вы знали бы меньше‹a‹верхнее, для небольшого диапазона, я бы использовал этот подход. - person ergonaut; 29.09.2015