Я пытаюсь реализовать алгоритм умножения Шёнхаге-Штрассена с использованием NTT и сталкиваюсь с проблемой, когда конечный результирующий вектор на самом деле не равен тому, чем он должен быть.
Для двух входных векторов a
и b
, каждый из которых состоит из N
"цифр" из K
битов (последние N/2
записи каждого набора равны 0), каждому из которых задан модуль M = 2^(2*K)+1
, корень из единицы w = N^(4*K-1) | w^N = 1 mod M
, модульная инверсия этого значения wi | wi*w = 1 mod M
и u | u*N = 1 mod M
, следующий код Python используется для (попытки) умножения этих векторов с помощью алгоритма Шёнхаге-Штрассена:
#a and b are lists of length N, representing large integers
A = [ sum([ (a[i]*pow(w,i*j,M))%M for i in range(N)]) for j in range(N)] #NTT of a
B = [ sum([ (b[i]*pow(w,i*j,M))%M for i in range(N)]) for j in range(N)] #NTT of b
C = [ (A[i]*B[i])%M for i in range(N)] #A * B multiplied pointwise
c = [ sum([ (C[i]*pow(wi,i*j,M))%M for i in range(N)]) for j in range(N)] #intermediate step in INTT of C
ci = [ (i*u)%M for i in c] #INTT of C, should be product of a and b
Теоретически, если я не ошибаюсь, взяв NTT для a
и b
, умножая по точкам, затем взяв INTT результата, должно получиться произведение, и я протестировал эти методы для NTT и INTT, чтобы подтвердить, что они инвертируют каждый Другие. Однако конечный результирующий вектор ci
, а не произведение a
и b
, является произведением, в котором каждый элемент берется по модулю M
, что дает неверный результат для произведения.
Например, запуск теста с N=K=8
и случайными векторами для a, b
дает следующее:
M = 2^(2*8)+1 = 65537
w = 16, wi = 61441
u = 57345
a = [212, 251, 84, 186, 0, 0, 0, 0] (3126131668 as an integer)
b = [180, 27, 234, 225, 0, 0, 0, 0] (3790216116)
NTT(a) = [733, 66681, 147842, 92262, 130933, 107825, 114562, 127302]
NTT(b) = [666, 64598, 80332, 54468, 131236, 186644, 181708, 88232]
Pointwise product of above two lines mod M = [29419, 39913, 25015, 14993, 42695, 49488, 52438, 51319]
INTT of above line (i.e. result) = [38160, 50904, 5968, 11108, 15616, 62424, 41850, 0] (11848430946168040720)
Actual product of a x b = [38160, 50904, 71505, 142182, 81153, 62424, 41850, 0] (11848714628791561488)
В этом примере и почти каждый раз, когда я его пробую, элементы реального продукта и результат моего алгоритма одинаковы для нескольких элементов около начала и конца вектора, но к середине они отклоняются. Как я упоминал выше, каждый элемент ci
равен элементам a*b
по модулю M
. Я, должно быть, неправильно понимаю этот алгоритм, хотя не совсем уверен, что именно. Я где-то использую неправильный модуль?