Matlab: решатель линейных конгруэнций, который поддерживает непростой модуль?
Я работаю над некоторым кодом Matlab для выполнения чего-то, называемого атакой на индексное исчисление для данной криптосистемы (это включает вычисление дискретных значений журнала), и я выполнил все это за исключением одной маленькой вещи. Я не могу понять (в Matlab), как решить линейную систему сравнений mod p, где p не простое число. Кроме того, эта система имеет более одной переменной, поэтому, если я что-то упустил, китайская теорема об остатках не сработает.
Я задал вопрос о математике обмена стеками с более подробным / отформатированным mathjax здесь. Я решил эту проблему в своем вопросе по этой ссылке, и теперь я пытаюсь найти утилиту, которая позволит мне решить систему сравнений по модулю не простых. Я нашел набор, который включает решатель, поддерживающий модульную арифметику, но модуль должен быть простым ( здесь). Я также попытался пройти, чтобы изменить его для работы с не простыми числами, но какой бы метод ни использовался, он не работает, потому что он требует, чтобы все элементы системы имели инверсии по модулю p.
Я рассмотрел возможность использования в Matlab возможности вызова функций MuPAD, но из моего тестирования функция MuPAD linsolve
(который казался лучшим кандидатом) также не поддерживает не простые значения модуля. Кроме того, я проверил с помощью Maple, что эта система разрешима по модулю моего целого числа интереса (8), так что это можно сделать.
Чтобы быть более конкретным, это именно та команда, которую я пытаюсь запустить в MuPAD:
linsolve([0*x + 5*y + 4*z + q = 2946321, x + 7*y + 2*q = 5851213, 8*x + y + 2*q = 2563617, 10*x + 5*y + z = 10670279],[x,y,z,q], Domain = Dom::IntegerMod(8))
Error: expecting 'Domain=R', where R is a domain of category 'Cat::Field' [linsolve]
Эта же команда возвращает правильные значения, если я изменю домен на IntegerMod(23) и IntegerMod(59407), поэтому я считаю, что 8 не подходит, потому что он не прост. Вот вывод, когда я пытаюсь использовать вышеуказанную команду с каждыми 23 и 59407 в качестве моего домена:
[x = 1 mod 23, y = 1 mod 23, z = 12 mod 23, q = 14 mod 23]
[x = 14087 mod 59407, y = 1 mod 59407, z = 14365 mod 59407, q = 37320 mod 59407]
Эти ответы верны x
, y
, z
, а также q
соответствовать L1
, L2
, L3
, а также L4
в системе сравнений, расположенной по моей ссылке Math.StackExchange выше.
1 ответ
Мне интересно, если вы пытались использовать sym/linsolve
а также sym/solve
ранее, но, возможно, были переданы в виде числовых, а не символических значений. Например, это возвращает бессмыслицу с точки зрения того, что вы ищете:
A = [0 5 4 1;1 7 0 2;8 1 0 2;10 5 1 0];
b = [2946321;5851213;2563617;10670279];
s = mod(linsolve(A,b),8)
Но если вы преобразуете числовые значения в символические целые числа, sym/linsolve
будет держать все в терминах рациональных дробей. затем
s = mod(linsolve(sym(A),sym(b)),8)
возвращает ожидаемый ответ
s =
6
1
6
4
Это просто решает системную линейную систему, используя символическую математику, как если бы она была нормальной матрицей. Для больших систем это может быть дорого, но я думаю, что не более, чем использование MuPAD numeric::linsolve
или же linalg::matlinsolve
, sym/mod
должен возвращать модуль числителя каждого компонента решения. Я полагаю, что вы получите ошибку, если модуль и знаменатель по крайней мере не взаимно просты.
sym/solve
также может быть использован для решения этой проблемы аналогичным образом:
L = sym('L',[4,1]);
[L1,L2,L3,L4] = solve(A*L==b);
s = mod([L1;L2;L3;L4],8)
Возможная проблема с использованием любого sym/solve
или же sym/linsolve
является то, что если существует несколько решений линейной проблемы конгруэнтности (в отличие от линейной системы), этот подход может не вернуть все из них.
Наконец, используя функцию MuPAD numlib:: ichrem (китайская теорема об остатках для целых чисел), вот код, который пытается получить полное решение:
A = [0 5 4 1;1 7 0 2;8 1 0 2;10 5 1 0];
b = [2946321;5851213;2563617;10670279];
m = 10930888;
mf = str2num(strrep(char(factor(sym(m))),'*',' '));
A = sym(A);
b = sym(b);
s = sym(zeros(length(b),length(mf)));
for i = 1:length(mf)
s(:,i) = mod(linsolve(A,b),mf(i));
end
mstr = ['[' sprintf('%d,',mf)];
mstr(end) = ']';
r = sym(zeros(length(b),1));
for i = 1:length(b)
sstr = char(s(i,:));
r(i) = feval(symengine,'numlib::ichrem',sstr(9:end-2),mstr);
end
check = isequal(mod(A*r,m),b)
Я не уверен, что это то, что вы ищете, но, надеюсь, это может быть полезно. Я думаю, что было бы хорошей идеей добавить запрос на расширение / обслуживание с MathWorks, чтобы MuPAD и другие решатели могли лучше обрабатывать системы в будущем.