-
Анатолий М. Георгиевский, ИТМО
Алгоритмы данной группы используются для генерации последовательности псеводслучайных чисел с однородным распределением.
Методы пригодны для параллельной реализации в задачах моделирования физических процессов. Основной показатель применимости методов для параллельных (высокопроизводительных) вычислений - это возможность получения последовательности с заданным отступом для распределения задачи между вычислительными ядрами, чтобы результат параллельной обработки давал в точности такой же результат, как и последовательное вычисление.
В данном проекте даются методы вычисления отсупов основанные на модульной арифметике большой разрядности (multi-prcision, см. mp.c).
Последовательность MWC — это последовательность пар
Последовательность с запаздыванием
Утверждение #1.
Доказательство:
Утверждение #2.
Если
$p = ab^r − 1$ является простым числом, то малая теорема Ферма гарантирует, что порядок любого элемента должен делиться на$p − 1 = ab^r − 2$ , поэтому один из способов обеспечить большой порядок — выбрать$a$ так, чтобы$p$ было «безопасным простым числом», то есть p и$(p − 1)/2 = ab^r/2 − 1$ были простыми числами. В таком случае для$b = 2^{32}$ и$r = 1$ период будет равен$ab^r/2 − 1$ , что приближается к$2^{63}$ , что на практике может быть приемлемо большим подмножеством числа возможных 32-битных пар$(x, c)$ . -- перевод с Wiki
Алгоритм разработан благодяря онлайн публикации MWC64x. К алгоритму приписал модульную арифметику с вычислением отступов для многопотокового вычисления.
Отступы (мещения сегментов) вычисляются по формуле
Генератор последовательности:
uint64_t next( uint64_t* state, const uint64_t A)
{
uint64_t x = *state;
*state = A*(uint32_t)(x) + (x>>32);
return x;
}
Таблица констант A для преобразования из диапазона 0xFFFF-0x1FFFF:
fffefd4e,fffefaa5,fffef712,fffef592,fffef0e2,fffeea1f,fffee9ad,fffee7b2,
fffee4e8,fffee42b,fffee2b4,fffedf2a,fffede76,fffedb10,fffed89a,fffed462,
fffed3ae,fffed024,fffecd60,fffecc43,fffecbc5,fffeca90,fffec289,fffebaeb,
fffeb81b,fffeb6f8,fffeaf24,fffea942,fffea759,fffea405,fffea2f7,fffe9e7a,
fffe9e65,fffe9835,fffe982c,fffe9736,fffe9664,fffe944e,fffe930d,fffe915a,
fffe9001,fffe8e66,fffe8c9b,fffe83aa,fffe81f1,fffe80ad,fffe7fa2,fffe7a2c,
fffe7594,fffe7369,fffe6fee,fffe6feb,fffe636a,fffe6337,fffe60af,fffe5bd5,
fffe5a0a,fffe59b0,fffe59a7,fffe53e3,fffe51fd,fffe4fcf,fffe4858,fffe4456,
fffe42fd,fffe3b6e,fffe398b,fffe358f,fffe2a76,fffe29b9,fffe1d0b,fffe1c03,
fffe1b3a,fffe1702,fffe1495,fffe0f01,fffe03e2,fffe03c4,fffe00f4,
Для поиска значений константы
-
$x^{p-1}\equiv 1 \bmod p$ тест Ферма -
$x^{(Ab/2-2)}\equiv 1 \bmod (Ab/2-1)$ тест Ферма -
$p$ - простое число, проверка по таблице -
$Ab/2-1$ - простое число, по таблице - Делимость
$p \bmod {24} = 23$ ,$A \bmod {3} = 0$ -
$\overline{A}-1$ - простое число
-
Все тесты 1,2,3,4 - вероятностные, мог пропустить составное число
-
Свойство 5 применяется для классификации простых чисел в тесте LLR
-
Тест 6 я применяю из собственных наблюдений.
-
Алгоритм генерации таблицы прстых чисел и проверка простоты по таблцие см. prime.c
Алгоритм возведения в сепень для теста Ферма, 64-битыне числа:
typedef unsigned int __attribute__((mode(TI))) uint128_t;
static uint64_t powm(const uint64_t b, uint64_t a, const uint64_t P)
{
uint64_t r = b;
uint64_t s = 1;
while (a!=0) {
if (a&1)
s = ((uint128_t)s*r)%P;
r = ((uint128_t)r*r)%P;
a>>=1;
}
return s;
}
Для поиска констант A дающих "безопасные простые числа" (safe prime) разработал свой тест, который воспроизводит все пункты из пердыдущего раздела в больших числах, см. mwc_prime.c. Тест вероятностный, выделяет огромное множество констант.
Тестом на простоту Ферма является утверждение
Для чисел вида
Тесты LLR рассматривают два случая для поиска начального значения
- когда
$P ≡ 7 (\bmod 24)$ последовательность Люка (Lucas) c начальным значением$V_k(4,1)$ . - когда
$P ≡ 23 (\bmod 24)$ с подбором такого p:jacobi(p-2, n)=+1
andjacobi(p+2, n)=-1
для последовательности Люка$V_k(p,1)$
Последовательность
и удволетворяет ряду свойств:
Операция сложения и умножения индексов посделовательности коммутативна.
Характеристическим многочленом последовательностей Люка
можно использовать для получения явных формул:
Как в модульной арифметике считать корень квадратный - не очевидно. Определение корня, как и обратного числа, можно дать через операцию возведения в степень. Проверкой является прямая операция возведения в квадрат и умножения на обратное число.
Подробнее см. Алгори́тм Тоне́лли — Ше́нкса
Для поиска начального значения
- [1] "Optimized Computation of the Jacobi Symbol" Jonas Lindstrøm & Kostas Kryptos Chalkias https://eprint.iacr.org/2024/1054
Символ Якоби является важным примитивом в криптографических приложениях, таких как проверка простоты, факторизация целых чисел.
- [2] "A simpler alternative to Lucas–Lehmer–Riesel primality test" Pavel Atnashev https://eprint.iacr.org/2023/195
В этой статье рассматривается применение теста Моррисона на простоту к числам вида
$k \cdot 2^n-1$ и находится простая общая формула, эквивалентная тесту Люка — Лемера и тесту Люка — Лемера — Ризеля на простоту.
Тест Люка–Лемера–Ризеля примет вид
Тест Моррисона дается реккурентной формулой последовательности Люка, с начальными значениями
Ниже привожу реализацию теста LLR для простых чисел вида
int llr_test(uint32_t P, uint32_t k)
{
const int Q = 1, n=16;
uint32_t N = (k<<n)-1;
while( !(jacobi(P-2, N)==1 && jacobi(P+2, N)==-1)) P++;
uint32_t v = P;
// 1.
uint32_t p = v;
uint32_t zv = 2;
for(int i=1;i<k; i++){
uint32_t y = subm(mulm(p,v,N), zv, N);
zv = v; v = y;
}
// 2.
for(int i=2; i<n; i++)
v = subm(sqrm(v, N), 2, N);
return (v==0);
}
В расчете используются: модульное умножение mulm
, возведение в квадрат sqrm
, и модульное вычитание subm
.
Алгоритм разбит на две части одна считает
Расчет
Для расчета больших чисел следует использовать алгоритмы с вычислительной сложностью
В модульной арифметике применется несколько вариантов алгоритмов умножения: бинарный слева-направо, справо-налево. И еще много вариантов ускорения за счет использования таблиц, в частности window-NAF и sliding-window и пр., подробнее см. методы умножения в эллиптической криптографии.
Для начала можно рассмотреть "простой" алгоритм умножения слева-направа.
Q ← point_init(P)
for j ← i − 1 downto 0 do
Q ← point_double(Q, N)
if (k[j] != 0)
Q ← point_add(Q, P,D,N)
return Q
Здесь мы вынужедены перейти к уравнениям в переменных
Метод удвоения:
Метод сложения точек:
Метод сложения точек для случая
Ниже представлен рабочий код, насколько это возможно, в человеко-читаемом виде:
uint32_t lucas_mul(uint32_t p, uint32_t k, uint32_t N)
{
lucas_t v = {.u=1, .v=p}; // Инициализация
uint32_t d = subm(sqrm(p, N), 4, N); // Дискриминант (D)
int i = 30-__builtin_clz(k);
for(; i>=0; --i) { // двоичное умножение слева-направо
v = lucas_dbl(v, N); // удвоение
if ((k>>i)&1)
v = lucas_add(v, p, d, N);// сложение
}
return v.v;
}
Подробности см. тест LLR для MWC32, тест LLR для констант MWC64.
Корнем квадратным
Для данного
Практически, в контексте данной темы, есть смысл рассматривать
Признаком существования квадратного корня является символ Лежандра (Символ Якоби).
Определение Целое число
Определение Пусть
-
$\left({\frac {a}{p}}\right)= 0$ , если$a$ делится на$p$ ; -
$\left({\frac {a}{p}}\right)=+1$ , если$a$ является квадратичным вычетом по модулю$p$ , но при этом$a$ не делится на$p$ ; -
$\left({\frac {a}{p}}\right)=-1$ , если$a$ является квадратичным невычетом по модулю$p$ .
Символ Якоби определяется для нечетного
где
Для вычисления сивмола Лежандра используется алгоритм вычисления Символа Якоби.
В данной работе представлена реализация алгоритма вычисления симовла Якоби [1], см. jacobi.c.
Практическое решение задачи поиска константы для 32 битных чисел дано двумя методами. Оба метода реализованы путем расчета всей последовательности.
- Путем тестирования множества простых чисел в диапазоне 512-1023
- Путем последовательного перебора чисел в диапазоне [0..1023]
Критерием выбора константы
Другой набор тестов включает однородность и возможность сжатия (муаровый узор на "салфетках"). Для исследования однородности использовалось построение изображений по большому числу циклов. Тесты наглядно показывают отсуствие водяных знаков при использовании младших 16-20 бит. Тест при числе проходов 0x7F (8 бит, grayscale):
Для повышения однородности следует использовать только четные вызовы функции или только нечетные вызовы функции. Для A=0xFE94 при большом колчиестве циклов 0x7FFF, Формат файла (Grayscale 16 бит):
"Безопасным простым" является P=0xfe9fffff (A=FEA0) с периодом повтора 0x7f4ffffe. Генератор последовательности:
uint32_t next( uint32_t* state, const uint32_t A)
{
uint32_t x = *state;
*state = A*(uint16_t)(x) + (x>>16);
return x;
}
Ниже привожу таблицу простых чисел
A=FFEA i=7ff4fffe ( 21), P mod 24 =23, A mod 3 =0
A=FFD7 i=7feb7ffe ( 40), P mod 24 = 7, A mod 3 =2
A=FFBD i=7fde7ffe ( 66), P mod 24 =23, A mod 3 =0
A=FFA8 i=7fd3fffe ( 87), P mod 24 =23, A mod 3 =0
A=FF9B i=7fcd7ffe (100), P mod 24 = 7, A mod 3 =2
A=FF81 i=7fc07ffe (126), P mod 24 =23, A mod 3 =0
A=FF80 i=7fbffffe (127), P mod 24 = 7, A mod 3 =2
A=FF7B i=7fbd7ffe (132), P mod 24 =23, A mod 3 =0
A=FF75 i=7fba7ffe (138), P mod 24 =23, A mod 3 =0
A=FF48 i=7fa3fffe (183), P mod 24 =23, A mod 3 =0
A=FF3F i=7f9f7ffe (192), P mod 24 =23, A mod 3 =0
A=FF3C i=7f9dfffe (195), P mod 24 =23, A mod 3 =0
A=FF2C i=7f95fffe (211), P mod 24 = 7, A mod 3 =2
A=FF09 i=7f847ffe (246), P mod 24 =23, A mod 3 =0
A=FF03 i=7f817ffe (252), P mod 24 =23, A mod 3 =0
A=FF00 i=7f7ffffe (255), P mod 24 =23, A mod 3 =0
A=FEEB i=7f757ffe (276), P mod 24 =23, A mod 3 =0
A=FEE4 i=7f71fffe (283), P mod 24 = 7, A mod 3 =2
A=FEA8 i=7f53fffe (343), P mod 24 = 7, A mod 3 =2
A=FEA5 i=7f527ffe (346), P mod 24 = 7, A mod 3 =2
A=FEA0 i=7f4ffffe (351), P mod 24 =23, A mod 3 =0
A=FE94 i=7f49fffe (363), P mod 24 =23, A mod 3 =0
A=FE8B i=7f457ffe (372), P mod 24 =23, A mod 3 =0
A=FE72 i=7f38fffe (397), P mod 24 = 7, A mod 3 =2
A=FE4E i=7f26fffe (433), P mod 24 = 7, A mod 3 =2
A=FE30 i=7f17fffe (463), P mod 24 = 7, A mod 3 =2
A=FE22 i=7f10fffe (477), P mod 24 =23, A mod 3 =0
A=FE15 i=7f0a7ffe (490), P mod 24 = 7, A mod 3 =2
A=FE04 i=7f01fffe (507), P mod 24 =23, A mod 3 =0
Все числа из таблицы проходят тест LLR.