Показаны сообщения с ярлыком CRT. Показать все сообщения
Показаны сообщения с ярлыком CRT. Показать все сообщения

понедельник, 22 сентября 2025 г.

Модульная арифметика со знаком для PQC

Наша задача реализация методов модульной арифметики для ZKP и PQC-пост-квантовой криптографии. Методов оказалось много. Раньше я ссылался на учебник [GECC] (сокр. Guide to Elliptic Curve Criptography), где разобраны разнообразные алгоритмы для криптографии, включая модульную арифметику и арифметику Галуа. В настоящее время появился ряд методов, к ним относятся, оптимизированные методы умножения Шоупа (Shoup) и Плантарда(Plantard, Thomas), а также новая тенденция в использовании модульной арифметики со знаком.

PQC - пост квантовая криптография основана на использование модульной арифметики в кольце полиномов с добавлением квантового шума Ring-LWE. Коэффициенты полиномов считаются в форме векторов длиной 256 элементов и выше.

ZKP - Zero-Knowledge Proof - концепция построения доказательства с нулевым разглашением, применяется например, для доказательства использования сложной функции без раскрытия информации о самой функции; для доказательства использования приватных данных без раскрытия данных. Применяется в распределенных вычислительных системах MPC - Multi-Party Computation.

Какой метод модульной арифметики может быть наиболее эффективным?
При выборе метода мы ориентируемся на систему команд целевой платформы: векторные инструкции CPU или GPU. И в настоящее время это должны быть 16/32/64 битные числа и вектора. Алгоритмы должны выражаться в векторных инструкциях сохраняющих разрядность элементов, таких как `mul_hi` - high product и `mul_lo` - low product, а также операции типа dot product с отложенным редуцированием по модулю могут дать прирост производительности. Операции могут быть с расширением знака или без знака. Заметим, что знаковая и беззнаковая операции умноженения идентичны signed low product и в целевой системе команд одна из операций может быть не представлена и выполняться через приведение типа. В системе команд могут быть представлены операции типа `madd` - умножения с накоплением и `msub` - умножение с вычитанием, в двух вариантах - старшая и младшая часть. Отдельно хочется упомянуть инструкции со странной разрядностью 52, которая рождается на месте мантиссы от double, в системе команд Intel AVX-IFMA.

Векторные инструкции не используют признаки переполнения и переноса разряда - это сильно осложняет реализацию методов для работы с большими числами произвольной разрядности. В этих случаях можно прибегнуть к непозиционной системе исчисления, основанной на CRT-китайской теореме об остатках, см. RNS-Residue Number System.

Оптимизированные алгоритмы опираются на сдвиг 16-, 32-, 52- или 64 бит и отложенное редуцирование Баррета при сложении и вычитании в ядре, при использовании модульных операций в цикле.

Algorithm 1.1. Signed Barrett modular reduction


*Require*: $0\lt q\lt\beta/2$, $-\beta q\leqslant z = z_1 \beta + z_0 \lt 2^{31}q$, где $-2^{31} \leqslant z_0 \lt 2^{31}$
*Require*: precomputed $u = \lfloor (2^{\lfloor \log(q)\rfloor -1} \beta)/q \rceil$
*Ensure*: Returns $r \equiv a \bmod^{\pm} q$ ; $-q\lt r \leqslant q$
  1. $t ← \lfloor au/\beta \rfloor \gg 2^{\lfloor \log(q)\rfloor -1}$ -- signed low product and arithmetic shift
  2. $t ← t \cdot q \bmod^{\pm} \beta$ -- signed low product
  3. $r ← z - t$ -- signed remainder

Algorithm 2. Montgomery's modular multiplication


*Require*: $b,w \in [0,p)$; $p\lt\beta/2$
*Require*: precomputed $J = p^{-1} \mod \beta$, $w' = \beta w \mod p$
*Ensure*: Returns $r = b\cdot w \mod p$
  1. $U = u_1\beta + u_0 ← bw'$ -- (wide product)
  2. $q ← u_0J \mod \beta$ -- (low product)
  3. $h ← \lfloor qp/\beta\rfloor$ -- (high product)
  4. $r ← u_1 - h$
  5. $r ← r + p$ if $r \lt 0$

последнюю строчку можно исключить, если принять $r \in (-p, p)$. Две последовательные операции _low product_ в строчке (1) и (2) можно объединить.

Algorithm 2.1. Signed Montgomery's modular multiplication


*Require*: $b,w \in [0,p)$; $p\lt\beta/2$
*Require*: precompute $J = p^{-1} \bmod^{\pm} \beta~$; $w' = w\beta \bmod p~$;
*Require*: precompute $\tilde{w} = w'\cdot J \bmod^{\pm} \beta$ -- (signed low product)
*Ensure*: Returns $r = b\cdot w \bmod^{\pm} p$
  1. $u_1 ← \lfloor bw'/\beta \rfloor$ -- (signed high product)
  2. $q ← b\tilde{w} \bmod^{\pm} \beta$ -- (signed low product)
  3. $t ← \lfloor qp/\beta\rfloor$ -- (signed high product)
  4. $r ← u_1 - t$

Для алгоритма важен метод вычисления обратного значения $p^{-1}$. Мы его вычисляем в 32 битных числах, потом приводим к знаковому типу $p^{-1} \bmod^{\pm} \beta$.

*Listing* Функция для вычисления $q^{-1} \bmod 2^{s}$, для $s\lt 32$:

uint32_t mod_inverse(uint32_t q, int s) {
    uint32_t q_inv = 1;
    for (int i = 1; i < s; i++) {
        if (((q * q_inv) & ((~0uL)>>(31-i))) != 1) {
            q_inv += (1u<<i);
        }
    }
    return q_inv;
}

Алгоритм -авторский, так и родился в виде программы. Базовая идея - инверсия по модулю должна давать единицу для любых s. Аналогичный метод может быть использован для нахождения константы при замене деления. Подобный метод возникал в конечных полях Галуа и все они, вероятно, могут быть выражены через расширенный алгоритм Евклида.