17db96d56Sopenharmony_ci#
27db96d56Sopenharmony_ci# Copyright (c) 2008-2020 Stefan Krah. All rights reserved.
37db96d56Sopenharmony_ci#
47db96d56Sopenharmony_ci# Redistribution and use in source and binary forms, with or without
57db96d56Sopenharmony_ci# modification, are permitted provided that the following conditions
67db96d56Sopenharmony_ci# are met:
77db96d56Sopenharmony_ci#
87db96d56Sopenharmony_ci# 1. Redistributions of source code must retain the above copyright
97db96d56Sopenharmony_ci#    notice, this list of conditions and the following disclaimer.
107db96d56Sopenharmony_ci#
117db96d56Sopenharmony_ci# 2. Redistributions in binary form must reproduce the above copyright
127db96d56Sopenharmony_ci#    notice, this list of conditions and the following disclaimer in the
137db96d56Sopenharmony_ci#    documentation and/or other materials provided with the distribution.
147db96d56Sopenharmony_ci#
157db96d56Sopenharmony_ci# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
167db96d56Sopenharmony_ci# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
177db96d56Sopenharmony_ci# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
187db96d56Sopenharmony_ci# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
197db96d56Sopenharmony_ci# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
207db96d56Sopenharmony_ci# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
217db96d56Sopenharmony_ci# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
227db96d56Sopenharmony_ci# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
237db96d56Sopenharmony_ci# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
247db96d56Sopenharmony_ci# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
257db96d56Sopenharmony_ci# SUCH DAMAGE.
267db96d56Sopenharmony_ci#
277db96d56Sopenharmony_ci
287db96d56Sopenharmony_ci
297db96d56Sopenharmony_ci######################################################################
307db96d56Sopenharmony_ci#  This file lists and checks some of the constants and limits used  #
317db96d56Sopenharmony_ci#  in libmpdec's Number Theoretic Transform. At the end of the file  #
327db96d56Sopenharmony_ci#  there is an example function for the plain DFT transform.         #
337db96d56Sopenharmony_ci######################################################################
347db96d56Sopenharmony_ci
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_ci#
377db96d56Sopenharmony_ci# Number theoretic transforms are done in subfields of F(p). P[i]
387db96d56Sopenharmony_ci# are the primes, D[i] = P[i] - 1 are highly composite and w[i]
397db96d56Sopenharmony_ci# are the respective primitive roots of F(p).
407db96d56Sopenharmony_ci#
417db96d56Sopenharmony_ci# The strategy is to convolute two coefficients modulo all three
427db96d56Sopenharmony_ci# primes, then use the Chinese Remainder Theorem on the three
437db96d56Sopenharmony_ci# result arrays to recover the result in the usual base RADIX
447db96d56Sopenharmony_ci# form.
457db96d56Sopenharmony_ci#
467db96d56Sopenharmony_ci
477db96d56Sopenharmony_ci# ======================================================================
487db96d56Sopenharmony_ci#                           Primitive roots
497db96d56Sopenharmony_ci# ======================================================================
507db96d56Sopenharmony_ci
517db96d56Sopenharmony_ci#
527db96d56Sopenharmony_ci# Verify primitive roots:
537db96d56Sopenharmony_ci#
547db96d56Sopenharmony_ci# For a prime field, r is a primitive root if and only if for all prime
557db96d56Sopenharmony_ci# factors f of p-1, r**((p-1)/f) =/= 1  (mod p).
567db96d56Sopenharmony_ci#
577db96d56Sopenharmony_cidef prod(F, E):
587db96d56Sopenharmony_ci    """Check that the factorization of P-1 is correct. F is the list of
597db96d56Sopenharmony_ci       factors of P-1, E lists the number of occurrences of each factor."""
607db96d56Sopenharmony_ci    x = 1
617db96d56Sopenharmony_ci    for y, z in zip(F, E):
627db96d56Sopenharmony_ci        x *= y**z
637db96d56Sopenharmony_ci    return x
647db96d56Sopenharmony_ci
657db96d56Sopenharmony_cidef is_primitive_root(r, p, factors, exponents):
667db96d56Sopenharmony_ci    """Check if r is a primitive root of F(p)."""
677db96d56Sopenharmony_ci    if p != prod(factors, exponents) + 1:
687db96d56Sopenharmony_ci        return False
697db96d56Sopenharmony_ci    for f in factors:
707db96d56Sopenharmony_ci        q, control = divmod(p-1, f)
717db96d56Sopenharmony_ci        if control != 0:
727db96d56Sopenharmony_ci            return False
737db96d56Sopenharmony_ci        if pow(r, q, p) == 1:
747db96d56Sopenharmony_ci            return False
757db96d56Sopenharmony_ci    return True
767db96d56Sopenharmony_ci
777db96d56Sopenharmony_ci
787db96d56Sopenharmony_ci# =================================================================
797db96d56Sopenharmony_ci#             Constants and limits for the 64-bit version
807db96d56Sopenharmony_ci# =================================================================
817db96d56Sopenharmony_ci
827db96d56Sopenharmony_ciRADIX = 10**19
837db96d56Sopenharmony_ci
847db96d56Sopenharmony_ci# Primes P1, P2 and P3:
857db96d56Sopenharmony_ciP = [2**64-2**32+1, 2**64-2**34+1, 2**64-2**40+1]
867db96d56Sopenharmony_ci
877db96d56Sopenharmony_ci# P-1, highly composite. The transform length d is variable and
887db96d56Sopenharmony_ci# must divide D = P-1. Since all D are divisible by 3 * 2**32,
897db96d56Sopenharmony_ci# transform lengths can be 2**n or 3 * 2**n (where n <= 32).
907db96d56Sopenharmony_ciD = [2**32 * 3    * (5 * 17 * 257 * 65537),
917db96d56Sopenharmony_ci     2**34 * 3**2 * (7 * 11 * 31 * 151 * 331),
927db96d56Sopenharmony_ci     2**40 * 3**2 * (5 * 7 * 13 * 17 * 241)]
937db96d56Sopenharmony_ci
947db96d56Sopenharmony_ci# Prime factors of P-1 and their exponents:
957db96d56Sopenharmony_ciF = [(2,3,5,17,257,65537), (2,3,7,11,31,151,331), (2,3,5,7,13,17,241)]
967db96d56Sopenharmony_ciE = [(32,1,1,1,1,1), (34,2,1,1,1,1,1), (40,2,1,1,1,1,1)]
977db96d56Sopenharmony_ci
987db96d56Sopenharmony_ci# Maximum transform length for 2**n. Above that only 3 * 2**31
997db96d56Sopenharmony_ci# or 3 * 2**32 are possible.
1007db96d56Sopenharmony_ciMPD_MAXTRANSFORM_2N = 2**32
1017db96d56Sopenharmony_ci
1027db96d56Sopenharmony_ci
1037db96d56Sopenharmony_ci# Limits in the terminology of Pollard's paper:
1047db96d56Sopenharmony_cim2 = (MPD_MAXTRANSFORM_2N * 3) // 2 # Maximum length of the smaller array.
1057db96d56Sopenharmony_ciM1 = M2 = RADIX-1                   # Maximum value per single word.
1067db96d56Sopenharmony_ciL = m2 * M1 * M2
1077db96d56Sopenharmony_ciP[0] * P[1] * P[2] > 2 * L
1087db96d56Sopenharmony_ci
1097db96d56Sopenharmony_ci
1107db96d56Sopenharmony_ci# Primitive roots of F(P1), F(P2) and F(P3):
1117db96d56Sopenharmony_ciw = [7, 10, 19]
1127db96d56Sopenharmony_ci
1137db96d56Sopenharmony_ci# The primitive roots are correct:
1147db96d56Sopenharmony_cifor i in range(3):
1157db96d56Sopenharmony_ci    if not is_primitive_root(w[i], P[i], F[i], E[i]):
1167db96d56Sopenharmony_ci        print("FAIL")
1177db96d56Sopenharmony_ci
1187db96d56Sopenharmony_ci
1197db96d56Sopenharmony_ci# =================================================================
1207db96d56Sopenharmony_ci#             Constants and limits for the 32-bit version
1217db96d56Sopenharmony_ci# =================================================================
1227db96d56Sopenharmony_ci
1237db96d56Sopenharmony_ciRADIX = 10**9
1247db96d56Sopenharmony_ci
1257db96d56Sopenharmony_ci# Primes P1, P2 and P3:
1267db96d56Sopenharmony_ciP = [2113929217, 2013265921, 1811939329]
1277db96d56Sopenharmony_ci
1287db96d56Sopenharmony_ci# P-1, highly composite. All D = P-1 are divisible by 3 * 2**25,
1297db96d56Sopenharmony_ci# allowing for transform lengths up to 3 * 2**25 words.
1307db96d56Sopenharmony_ciD = [2**25 * 3**2 * 7,
1317db96d56Sopenharmony_ci     2**27 * 3    * 5,
1327db96d56Sopenharmony_ci     2**26 * 3**3]
1337db96d56Sopenharmony_ci
1347db96d56Sopenharmony_ci# Prime factors of P-1 and their exponents:
1357db96d56Sopenharmony_ciF = [(2,3,7), (2,3,5), (2,3)]
1367db96d56Sopenharmony_ciE = [(25,2,1), (27,1,1), (26,3)]
1377db96d56Sopenharmony_ci
1387db96d56Sopenharmony_ci# Maximum transform length for 2**n. Above that only 3 * 2**24 or
1397db96d56Sopenharmony_ci# 3 * 2**25 are possible.
1407db96d56Sopenharmony_ciMPD_MAXTRANSFORM_2N = 2**25
1417db96d56Sopenharmony_ci
1427db96d56Sopenharmony_ci
1437db96d56Sopenharmony_ci# Limits in the terminology of Pollard's paper:
1447db96d56Sopenharmony_cim2 = (MPD_MAXTRANSFORM_2N * 3) // 2 # Maximum length of the smaller array.
1457db96d56Sopenharmony_ciM1 = M2 = RADIX-1                   # Maximum value per single word.
1467db96d56Sopenharmony_ciL = m2 * M1 * M2
1477db96d56Sopenharmony_ciP[0] * P[1] * P[2] > 2 * L
1487db96d56Sopenharmony_ci
1497db96d56Sopenharmony_ci
1507db96d56Sopenharmony_ci# Primitive roots of F(P1), F(P2) and F(P3):
1517db96d56Sopenharmony_ciw = [5, 31, 13]
1527db96d56Sopenharmony_ci
1537db96d56Sopenharmony_ci# The primitive roots are correct:
1547db96d56Sopenharmony_cifor i in range(3):
1557db96d56Sopenharmony_ci    if not is_primitive_root(w[i], P[i], F[i], E[i]):
1567db96d56Sopenharmony_ci        print("FAIL")
1577db96d56Sopenharmony_ci
1587db96d56Sopenharmony_ci
1597db96d56Sopenharmony_ci# ======================================================================
1607db96d56Sopenharmony_ci#                 Example transform using a single prime
1617db96d56Sopenharmony_ci# ======================================================================
1627db96d56Sopenharmony_ci
1637db96d56Sopenharmony_cidef ntt(lst, dir):
1647db96d56Sopenharmony_ci    """Perform a transform on the elements of lst. len(lst) must
1657db96d56Sopenharmony_ci       be 2**n or 3 * 2**n, where n <= 25. This is the slow DFT."""
1667db96d56Sopenharmony_ci    p = 2113929217             # prime
1677db96d56Sopenharmony_ci    d = len(lst)               # transform length
1687db96d56Sopenharmony_ci    d_prime = pow(d, (p-2), p) # inverse of d
1697db96d56Sopenharmony_ci    xi = (p-1)//d
1707db96d56Sopenharmony_ci    w = 5                         # primitive root of F(p)
1717db96d56Sopenharmony_ci    r = pow(w, xi, p)             # primitive root of the subfield
1727db96d56Sopenharmony_ci    r_prime = pow(w, (p-1-xi), p) # inverse of r
1737db96d56Sopenharmony_ci    if dir == 1:      # forward transform
1747db96d56Sopenharmony_ci        a = lst       # input array
1757db96d56Sopenharmony_ci        A = [0] * d   # transformed values
1767db96d56Sopenharmony_ci        for i in range(d):
1777db96d56Sopenharmony_ci            s = 0
1787db96d56Sopenharmony_ci            for j in range(d):
1797db96d56Sopenharmony_ci                s += a[j] * pow(r, i*j, p)
1807db96d56Sopenharmony_ci            A[i] = s % p
1817db96d56Sopenharmony_ci        return A
1827db96d56Sopenharmony_ci    elif dir == -1: # backward transform
1837db96d56Sopenharmony_ci        A = lst     # input array
1847db96d56Sopenharmony_ci        a = [0] * d # transformed values
1857db96d56Sopenharmony_ci        for j in range(d):
1867db96d56Sopenharmony_ci            s = 0
1877db96d56Sopenharmony_ci            for i in range(d):
1887db96d56Sopenharmony_ci                s += A[i] * pow(r_prime, i*j, p)
1897db96d56Sopenharmony_ci            a[j] = (d_prime * s) % p
1907db96d56Sopenharmony_ci        return a
1917db96d56Sopenharmony_ci
1927db96d56Sopenharmony_cidef ntt_convolute(a, b):
1937db96d56Sopenharmony_ci    """convolute arrays a and b."""
1947db96d56Sopenharmony_ci    assert(len(a) == len(b))
1957db96d56Sopenharmony_ci    x = ntt(a, 1)
1967db96d56Sopenharmony_ci    y = ntt(b, 1)
1977db96d56Sopenharmony_ci    for i in range(len(a)):
1987db96d56Sopenharmony_ci        y[i] = y[i] * x[i]
1997db96d56Sopenharmony_ci    r = ntt(y, -1)
2007db96d56Sopenharmony_ci    return r
2017db96d56Sopenharmony_ci
2027db96d56Sopenharmony_ci
2037db96d56Sopenharmony_ci# Example: Two arrays representing 21 and 81 in little-endian:
2047db96d56Sopenharmony_cia = [1, 2, 0, 0]
2057db96d56Sopenharmony_cib = [1, 8, 0, 0]
2067db96d56Sopenharmony_ci
2077db96d56Sopenharmony_ciassert(ntt_convolute(a, b) == [1,        10,        16,        0])
2087db96d56Sopenharmony_ciassert(21 * 81             == (1*10**0 + 10*10**1 + 16*10**2 + 0*10**3))
209