Модульный обратный расчет - PullRequest
0 голосов
/ 30 октября 2019

Если заданы произвольные целые числа p, g и r и дано y, такое, что <em>y = g<sup>x</sup></em> mod <em>p</em>, где x - неизвестное целое число, как можно решить для C, где <em>C = g<sup>r</sup>• (g<sup>x</sup>)<sup>-1</sup></em> mod <em>p</em>?

Моя математика ниже, но когда я ввожу ее в функцию верификатора, он говорит, что ответ неправильный.

    <i>y•u = 1 mod p</i>

    <i>y•u = 1 + mp</i>
    <i>uy - mp = 1</i>

, где u - обратное значение yи m - набор натуральных чисел (как того требует обратный мод)

1 Ответ

0 голосов
/ 30 октября 2019

Если я правильно понял, вы ищете Обратный мод . Математика выглядит следующим образом:

ab = a^b % p
ab + c*p = a^b
log(ab+c*p)/log(a) = b
(ab+c*p)^(1/b) = a

, где c - целое число c={ 0,1,2,3,4... }, преобразовывающее между нормальной и модульной арифметикой. Так что в вашем случае вы хотите вычислить b. Проблема в том, что log(ab+c*p)/log(a) растет очень медленно с увеличением c, если p не намного больше, чем a. Таким образом, в таком случае быстрее использовать все комбинации b, пока в C ++ не будет найдено что-то похожее:

//---------------------------------------------------------------------------
ALU32 alu;
DWORD modmul(DWORD a,DWORD b,DWORD p)   //  ans = a*b % p
    {
    DWORD ch,cl,c,d;
    alu.mul(ch,cl,a,b);
    alu.div(c,d,ch,cl,p);
    return d;
    }
//---------------------------------------------------------------------------
DWORD modinv(DWORD a,DWORD p)   //  a * ans % p = 1
    {
    DWORD b,c,db,dc,i=0;
    db=p/a;
    dc=db*a;
    for (b=1,c=a;b<p;i++)
        {
        if (c==1) return b;
        b+=db; c+=dc;
        while (c<p){ b++; c+=a; }
        c-=p;
        }
    return 0;
    }
//---------------------------------------------------------------------------

DWORD modpow(DWORD a,DWORD b,DWORD p)   //  ans = a^b % p
    {   // b is not mod(p) !
    DWORD i,d=1;
    for (a%=p,i=0;i<32;i++,b<<=1)
        {
        d=modmul(d,d,p);
        if (DWORD(b&0x80000000)) d=modmul(d,a,p);
        }
    return d;
    }
//---------------------------------------------------------------------------
DWORD imodpow(DWORD ab,DWORD a,DWORD p) // ab = a^ans % p
    { // ans is not mod(p) !
    DWORD b,AB;
    for (AB=1,b=0;;)
        {
        if (AB==ab) return b;
        b++; if (!b) return  0;
        AB=modmul(AB,a,p);
        }
    }
//---------------------------------------------------------------------------

грубо, это SLOOOOW, поэтому оно используется для криптографии. Также будьте осторожны, существует несколько допустимых решений , и первое найденное может быть не тем, которое вы ищете, поэтому вам нужно добавить дополнительные условия ...

ALU32.h может бытьможно найти здесь Не могу сделать, чтобы значение распространялось через перенос

И модульная арифметика основана на этом: Модульная арифметика и оптимизация NTT (конечное поле DFT)

Вот пример для сравнения (игнорируйте функции VCL и TBEG / TED / TSTR):

DWORD a=87654321,b=12345678,p=0xC0000001,ab,bb;
tbeg(); ab=modpow(a,b,p); tend();   mm_log->Lines->Add(AnsiString().sprintf("%8u^%8u mod %u = %u ",a,b ,p,ab)+tstr(1));
tbeg(); bb=imodpow(ab,a,p); tend(); mm_log->Lines->Add(AnsiString().sprintf("%8u^%8u mod %u = %u ",a,bb,p,ab)+tstr(1));

и вывод:

87654321^12345678 mod 3221225473 = 3038293251 [   0.002 ms]
87654321^12345678 mod 3221225473 = 3038293251 [ 421.910 ms]

PS.

Могут быть некоторые более продвинутые подходы из теории чисел, если p особенный, как простое, составное из двух простых или даже n-го корня из единства ... но это в галактике очень далеко от моей досягаемостиэкспертизы.

[edit1]

из недавно опубликованного вопроса , наконец, стало более ясно, что вы на самом деле просто хотели модульное обратное и не имеете ничего общего с imodpow. Итак, что вы хотите, это:

a*b % p = 1

, где b неизвестно, поэтому просто попробуйте все b в возрастающей манере, где a*b % p просто усекается на p до нуля, и если результат1 вы нашли свой ответ. Я обновил код выше с помощью функции modinv, сделав именно это + некоторая оптимизация. Однако я думаю, что есть еще более быстрые подходы для этого с использованием GCD или чего-то еще.

Вот еще один тестовый образец:

DWORD a=87654321,b=12345678,p=0xC0000001,ab,bb;

        ab=modmul(a,b,p);
tbeg(); bb=modinv(b,p);     tend(); mm_log->Lines->Add(AnsiString().sprintf("       1/%8u mod %u = %u ",b,p,bb)+tstr(1));
tbeg(); a =modmul(b,bb,p);  tend(); mm_log->Lines->Add(AnsiString().sprintf("%8u*%8u mod %u = %u ",b,bb,p,a)+tstr(1));
tbeg(); a =modmul(ab,bb,p); tend(); mm_log->Lines->Add(AnsiString().sprintf("%8u*%8u mod %u = %u ",ab,bb,p,a)+tstr(1));

И вывод:

       1/12345678 mod 3221225473 = 165081805  [   4.999 ms]
12345678*165081805 mod 3221225473 = 1         [   0.000 ms]
652073126*165081805 mod 3221225473 = 87654321 [   0.000 ms]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...