Preliminary NIST FIPS 203 Results © Monday, February 16, 2026, by James Pate Williams, Jr. C Implementation

References:

  1. Module-Lattice-Based Key-Encapsulation Mechanism Standard
  2. Number-theoretic transform (integer DFT)
  3. chap2.pdf Chapter 2 of the Handbook of Applied Cryptography

I have two versions of the code using C long integers and another variant using Professor Emeritus Arjen K. Lenstra’s C Free Large Integer Package (lip).

Testing NIST BitRev
Primitive root = 17
Length = 7
n = 256
n / 2 = 128
q = 3329
BitRev(0) = 1
BitRev(1) = 1729
BitRev(2) = 2580
BitRev(3) = 3289
BitRev(4) = 2642
BitRev(5) = 630
BitRev(6) = 1897
BitRev(7) = 848
Testing NIST NTT
f[0] = 4 fhat[0] = 257
f[1] = 1 fhat[1] = 95
f[2] = 4 fhat[2] = 308
f[3] = 2 fhat[3] = 232
f[4] = 1 fhat[4] = 90
f[5] = 3 fhat[5] = 657
f[6] = 5 fhat[6] = 34
f[7] = 6 fhat[7] = 366
Testing NIST NTT^-1
fhat[0] = 257 copf[0] = 4
fhat[1] = 95 copf[1] = 1
fhat[2] = 308 copf[2] = 4
fhat[3] = 232 copf[3] = 2
fhat[4] = 90 copf[4] = 1
fhat[5] = 657 copf[5] = 3
fhat[6] = 34 copf[6] = 5
fhat[7] = 366 copf[7] = 6
Testing NIST NTT Multiplication
g[0] = 6 ghat[0] = 518 copg[0] = 6
g[1] = 1 ghat[1] = 661 copg[1] = 1
g[2] = 8 ghat[2] = 492 copg[2] = 8
g[3] = 0 ghat[3] = 339 copg[3] = 0
g[4] = 3 ghat[4] = 583 copg[4] = 3
g[5] = 3 ghat[5] = 91 copg[5] = 3
g[6] = 9 ghat[6] = 450 copg[6] = 9
g[7] = 8 ghat[7] = 259 copg[7] = 8
fhat[0] = 257 ghat[0] = 518 hhat[0] = 102
fhat[1] = 95 ghat[1] = 661 hhat[1] = 362
fhat[2] = 308 ghat[2] = 492 hhat[2] = 392
fhat[3] = 232 ghat[3] = 339 hhat[3] = 504
fhat[4] = 90 ghat[4] = 583 hhat[4] = 150
fhat[5] = 657 ghat[5] = 91 hhat[5] = 208
fhat[6] = 34 ghat[6] = 450 hhat[6] = 196
fhat[7] = 366 ghat[7] = 259 hhat[7] = 545

D:\NISTFIPS203\x64\Release\NISTFIPS203.exe (process 26656) exited with code 0 (0x0).
Press any key to close this window . . .

Blog Entry © Thursday, October 23, 2025, by James Pate Williams, Jr. A Stochastic ProblemRelated to the Subset Sum Problem

Blog Entry © Tuesday, October 21, 2025, by James Pate Williams, Jr., Solving Low Density Subset Sum Problems Using the LLL-Lattice Reduction Algorithm

// Algorithm found in the "Handbook of
// Applied Cryptography" (c) 1997 by
// Alfred J. Menezes, Paul C van Oorschot,
// and Scott Vanstone 3.105 Algorithm
// Chapter 3 pages 120 - 121

#pragma once
class LLL_Lattice
{

private:

	static double Scalar(
		int n,
		std::vector<double> u,
		std::vector<double> v);
	static void RED(
		int k, int l, int n,
		std::vector<std::vector<double>>& b,
		std::vector<std::vector<double>>& h,
		std::vector<std::vector<double>>& mu);
	static void SWAP(
		int k, int k1, int kmax, int n,
		double m, std::vector<double>& B,
		std::vector<std::vector<double>>& b,
		std::vector<std::vector<double>>& bs,
		std::vector<std::vector<double>>& h,
		std::vector<std::vector<double>>& mu);

public:

	static bool LLL(
		int n,
		std::vector<std::vector<double>>& b,
		std::vector<std::vector<double>>& h);
};

#include "pch.h"
#include "LLL_Lattice.h"

double LLL_Lattice::Scalar(
    int n,
    std::vector<double> u,
    std::vector<double> v)
{
    // Calculate the scalar product of two vectors [1..n]
    double sum = 0.0;

    for (int i = 1; i <= n; i++) sum += u[i] * v[i];
    return sum;
}

void LLL_Lattice::RED(
    int k, int l, int n,
    std::vector<std::vector<double>>& b,
    std::vector<std::vector<double>>& h,
    std::vector<std::vector<double>>& mu)
{
    int i, q = (int)(0.5 + mu[k][l]);

    if (fabs(mu[k][l]) > 0.5)
    {
        for (i = 1; i <= n; i++)
        {
            b[k][i] -= q * b[l][i];
            h[i][k] -= q * h[i][l];
        }

        mu[k][l] -= q;

        for (i = 1; i <= l - 1; i++)
        {
            mu[k][i] -= q * mu[l][i];
        }
    }
}

void LLL_Lattice::SWAP(
    int k, int k1, int kmax, int n,
    double m, std::vector<double>& B,
    std::vector<std::vector<double>>& b,
    std::vector<std::vector<double>>& bs,
    std::vector<std::vector<double>>& h,
    std::vector<std::vector<double>>& mu)
{
    double C, t;
    int i, j;
    std::vector<double> c(n + 1);

    for (j = 1; j <= n; j++)
    {
        t = b[k][j];
        b[k][j] = b[k1][j];
        b[k1][j] = t;
        t = h[j][k];
        h[j][k] = h[j][k1];
        h[j][k1] = t;
    }

    if (k > 2)
    {
        for (j = 1; j <= k - 2; j++)
        {
            t = mu[k][j];
            mu[k][j] = mu[k1][j];
            mu[k1][j] = t;
        }
    }

    C = B[k] + m * m * B[k1];
    mu[k][k1] = m * B[k1] / C;

    for (i = 1; i <= n; i++)
    {
        c[i] = bs[k1][i];
    }

    for (i = 1; i <= n; i++)
    {
        bs[k1][i] = bs[k][i] + m * c[i];
    }
    
    for (i = 1; i <= n; i++)
    {
        bs[k][i] = -m * bs[k][i] + B[k] * c[i] / C;
    }

    B[k] *= B[k1] / C;
    B[k1] = C;

    for (i = k + 1; i <= kmax; i++)
    {
        t = mu[i][k];
        mu[i][k] = mu[i][k1] - m * t;
        mu[i][k1] = t + mu[k][k1] * mu[i][k];
    }
}

bool LLL_Lattice::LLL(
    int n,
    std::vector<std::vector<double>>& b,
    std::vector<std::vector<double>>& h)
{
    // Lattice reduction algorithm
 
    double m;
    std::vector<double> B(n + 1);
    std::vector<double> bv(n + 1);
    std::vector<double> bw(n + 1);
    std::vector<std::vector<double>> bs(n + 1,
        std::vector<double>(n + 1));
    std::vector<std::vector<double>> mu(n + 1,
        std::vector<double>(n + 1));
    int i, j, k, k1, kmax = 1, l;

    for (i = 1; i <= n; i++)
        bv[i] = bs[1][i] = b[1][i];

    B[1] = Scalar(n, bv, bv);

    for (i = 1; i <= n; i++)
    {
        for (j = 1; j <= n; j++)
        {
            h[i][j] = 0.0;
        }
        
        h[i][i] = 1.0;
    }

    for (k = 2; k <= n; k++)
    {
        if (k <= kmax)
            goto Label3;

        kmax = k;
        for (i = 1; i <= n; i++)
        {
            bs[k][i] = b[k][i];
        }

        for (j = 1; j <= k - 1; j++)
        {
            for (l = 1; l <= n; l++)
            {
                bv[l] = b[k][l];
                bw[l] = bs[j][l];
            }

            mu[k][j] = Scalar(n, bv, bw) / B[j];

            for (i = 1; i <= n; i++)
            {
                bs[k][i] -= mu[k][j] * bs[j][i];
            }
        }

        for (i = 1; i <= n; i++)
        {
            bv[i] = bs[k][i];
        }

        B[k] = Scalar(n, bv, bv);

        if (B[k] == 0.0)
            return false;

    Label3:

        k1 = k - 1;
        m = mu[k][k1];
        RED(k, k1, n, b, h, mu);

        if (B[k] < (0.75 - m * m) * B[k1])
        {
            SWAP(k, k1, kmax, n, m, B, b, bs, h, mu);
            k = max(2, k1);
            goto Label3;
        }

        for (l = k - 2; l >= 1; l--)
        {
            RED(k, l, n, b, h, mu);
        }
    }

    return true;
}

Blog Entry (c) Tuesday, August 27, 2024, Graphing New Goldwasser-Kilian Primality Test Results by James Pate Williams, Jr.

The x -axis is the number to be tested, the y-axis is prime number bound for factoring, and the z-axis is the runtime in seconds.

Blog Entry (c) Wednesday, August 21, 2024, by James Pate Williams, Jr. New and Improved Version of the Goldwasser-Kilian Primality Test

I corrected my powering modulo a prime routine. I added Pollard’s p – 1 factoring method and Shanks-Mestre elliptic curve point counting algorithm.

number to be tested or 0 to quit:
10000019
number of primes in factor base:
10000
Prime sieving time = 3.220000
N[0] = 10000019
a = 7838973
b = 2449531
m = 9995356
q = 356977
P = (9786147, 3226544)
P1 = (0, 1)
P2 = (5887862, 8051455)
N[1] = 356977
a = 45561
b = 178451
m = 357946
q = 178973
P = (80627, 163299)
P1 = (0, 1)
P2 = (52101, 282559)
N[2] = 178973
a = 135281
b = 76426
m = 178996
q = 73
P = (10238, 98035)
P1 = (0, 1)
P2 = (46702, 94326)
number is proven prime
runtime in seconds = 35.471000

number to be tested or 0 to quit:
10015969
number of primes in factor base:
10000
Prime sieving time = 3.424000
N[0] = 10015969
a = 6613193
b = 3951715
m = 10013908
q = 2503477
P = (998314, 8329764)
P1 = (0, 1)
P2 = (6944357, 1053776)
N[1] = 2503477
a = 1175442
b = 379813
m = 2505736
q = 293
P = (646462, 1631861)
P1 = (0, 1)
P2 = (1477980, 88719)
number is proven prime
runtime in seconds = 5.612000

number to be tested or 0 to quit:
99997981
number of primes in factor base:
10000
Prime sieving time = 4.152000
N[0] = 99997981
a = 34129462
b = 80482974
m = 100001414
q = 181
P = (19305995, 40493835)
P1 = (0, 1)
P2 = (33828245, 72969559)
number is proven prime
runtime in seconds = 11.500000

number to be tested or 0 to quit:
100001819
number of primes in factor base:
100000
Prime sieving time = 3.218000
N[0] = 100001819
a = 2694060
b = 17329746
m = 100008102
q = 5569
P = (124594, 14596756)
P1 = (0, 1)
P2 = (32514144, 56926555)
number is proven prime
runtime in seconds = 76.301000

number to be tested or 0 to quit:
100005317
number of primes in factor base:
100000
Prime sieving time = 3.269000
N[0] = 100005317
a = 45478318
b = 328034
m = 99988256
q = 3124633
P = (62548529, 30179124)
P1 = (0, 1)
P2 = (70379514, 76899689)
N[1] = 3124633
a = 2605576
b = 1809212
m = 3127654
q = 503
P = (1236288, 2081401)
P1 = (0, 1)
P2 = (2264479, 2583693)
number is proven prime
runtime in seconds = 459.979000

number to be tested or 0 to quit:
100000007
number of primes in factor base:
100000
Prime sieving time = 3.209000
N[0] = 100000007
a = 50593669
b = 72502607
m = 100005736
q = 2053
P = (72365335, 69885097)
P1 = (0, 1)
P2 = (55023241, 20078454)
number is proven prime
runtime in seconds = 163.705000

number to be tested or 0 to quit:
100014437
number of primes in factor base:
100000
Prime sieving time = 3.919000
N[0] = 100014437
a = 49955472
b = 45482796
m = 100024160
q = 263
P = (41650735, 8652103)
P1 = (0, 1)
P2 = (53790105, 37282431)
number is proven prime
runtime in seconds = 12.915000

Blog Entry (c) Wednesday, August 21, 2024, by James Pate Williams, Jr. Single Precision (64-Bit) Version of Pollard’s P-1 Factoring Method

prime number sieve creation
time in seconds = 3.483000
number to be factored or 0 to quit:
2111222333
1 11 1 p
2 17 1 p
3 11289959 1 p
factoring time in seconds = 0.063000
number to be factored or 0 to quit:
1234567890
1 2 1 p
2 3 2 p
3 5 1 p
4 3607 1 p
5 3803 1 p
factoring time in seconds = 0.133000
number to be factored or 0 to quit:
2^30+0
prime powers are not allowed
number to be factored or 0 to quit:
0

Blog Entry (c) Tuesday, August 20, 2024, by James Pate Williams, Jr. More Goldwasser-Kilian Primality Results (64-Bit Version which I call Single Precision)

Blog Entry (c) Monday, August 19, 2024, by James Pate Williams, Jr. Results from a Corrected Version of my Implementation of the 64-Bit Goldwasser-Kilian Primality Test

Blog Entry (c) Saturday, August 10, 2024, by James Pate Williams, Jr. The LLL Lattice Reduction Algorithm

Factorizations of Some Fibonacci Sequence Numbers, Lucas Sequence Numbers and Some Other Numbers Using Arjen K. Lenstra’s Free Large Integer Package and the Elliptic Curve Method (c) January 28, 2024, by James Pate Williams, Jr.

All of the following computations were performed on a late 2015 Dell XPS 8900 personal computer with a 64-bit Intel Core I7 processor @ 4.0GHz with 16GB of DDR2 RAM.

Factorization of Six Fibonacci Sequence Numbers:

Fibonacci 500
# digits 105
5 ^ 2 p # digits 1
15 c # digits 2
101 p # digits 3
401 p # digits 3
1661 c # digits 4
3001 p # digits 4
10291 c # digits 5
570601 p # digits 6
112128001 p # digits 9
1353439001 p # digits 10
28143378001 p # digits 11
5465167948001 p # digits 13
84817574770589638001 p # digits 20
158414167964045700001 p # digits 21
Runtime (s) = 1.206000

Fibonacci 505
# digits 106
5 p # digits 1
743519377 p # digits 9
44614641121 p # digits 11
770857978613 p # digits 12
960700389041 p # digits 12
12588421794766514566269164716286291055826556238643852856601641 p # digits 62
Runtime (s) = 1.959000

Fibonacci 510
# digits 107
2 ^ 3 p # digits 1
11 p # digits 2
61 p # digits 2
1021 p # digits 4
1597 p # digits 4
3469 p # digits 4
3571 p # digits 4
9521 p # digits 4
53551 p # digits 5
95881 p # digits 5
142445 c # digits 6
1158551 p # digits 7
3415914041 p # digits 10
20778644396941 p # digits 14
20862774425341 p # digits 14
81358225616651 c # digits 14
162716451241291 p # digits 15
Runtime (s) = 2.682000

Fibonacci 515
# digits 108
5 p # digits 1
519121 p # digits 6
5644193 p # digits 7
512119709 p # digits 9
84388938382141 p # digits 14
300367026458796424297447559250634818495937628065437243817852436228914621 p # digits 72
Runtime (s) = 7.861000

Fibonacci 520
# digits 109
131 p # digits 3
451 c # digits 3
521 p # digits 3
2081 p # digits 4
2161 p # digits 4
3121 p # digits 4
24571 p # digits 5
90481 p # digits 5
2519895 c # digits 7
21183761 p # digits 8
57089761 p # digits 8
102193207 p # digits 9
1932300241 p # digits 10
14736206161 p # digits 11
5836312049326721 p # digits 16
42426476041450801 p # digits 17
Runtime (s) = 5.155000

Fibonacci 525
# digits 110
2 p # digits 1
5 p # digits 1
421 p # digits 3
701 p # digits 3
3001 p # digits 4
3965 c # digits 4
4201 p # digits 4
141961 p # digits 6
2553601 p # digits 7
230686501 p # digits 9
8288823481 p # digits 10
82061511001 p # digits 11
19072991752501 c # digits 14
8481116649425701 p # digits 16
17231203730201189308301 p # digits 23
Runtime (s) = 2.026000


Factorization of Six Lucas Sequence Numbers

Lucas 340
113709744839525149336680459091826532688903186653162057995534262332121127
# digits 72
7 p # digits 1
2161 p # digits 4
5441 p # digits 4
897601 p # digits 6
23230657239121 p # digits 14
17276792316211992881 p # digits 20
3834936832404134644974961 p # digits 25
Runtime (s) = 109.103000

Lucas 345
# digits 73
2 ^ 2 p # digits 1
31 p # digits 2
461 p # digits 3
1151 p # digits 4
1529 c # digits 4
324301 p # digits 6
686551 p # digits 6
1485571 p # digits 7
4641631 p # digits 7
19965899801 c # digits 11
117169733521 p # digits 12
3490125311294161 p # digits 16
Runtime (s) = 0.032000


Lucas 350
13985374084677485786380981408251904922622980674054858121032362563653278123
# digits 74
3 p # digits 1
401 p # digits 3
2801 p # digits 4
11521 c # digits 5
28001 p # digits 5
570601 p # digits 6
12317523121 p # digits 11
248773766357061401 p # digits 18
7358192362316341243805801 p # digits 25
Runtime (s) = 21.047000


Lucas 355
69362907070206748494476200566565775354902428015845969798000696945226974645
# digits 74
5 p # digits 1
4261 p # digits 4
6673 p # digits 4
75309701 p # digits 8
309273161 p # digits 9
46165371073 p # digits 11
9207609261398081 p # digits 16
49279722643391864192801 p # digits 23
Runtime (s) = 40.726000


Lucas 360
769246427201094785080787978422393713094534885688979999504447628313150135520
# digits 75
2 ^ 5 p # digits 1
3 ^ 2 p # digits 1
23 p # digits 2
41 p # digits 2
105 c # digits 3
107 p # digits 3
241 p # digits 3
2161 p # digits 4
2521 p # digits 4
3439 c # digits 4
8641 p # digits 4
20641 p # digits 5
103681 p # digits 6
109441 p # digits 6
191306797 c # digits 9
10783342081 p # digits 11
13373763765986881 p # digits 17
Runtime (s) = 0.032000


Lucas 365
19076060504701386559675231910437330047906343529583769121365013189782992678011
# digits 77
11 p # digits 2
151549 p # digits 6
514651 p # digits 6
7015301 p # digits 7
8942501 p # digits 7
9157663121 p # digits 10
11899937029 p # digits 11
3252336525249736694804553589211 p # digits 31


The following two numbers were first factorized by J. M. Pollard on an 8-bit Phillips P2012 personal computer with 64 KB RAM and two 640 KB disc drives. The times required by Pollard were 41 and 47 hours.

2^144-3
22300745198530623141535718272648361505980413
# digits 44
492729991333 p # digits 12
45259565260477899162010980272761 p # digits 32
Runtime (s) = 0.086000


2^153+3
11417981541647679048466287755595961091061972995
# digits 47
5 p # digits 1
11 p # digits 2
600696432006490087537 p # digits 21
345598297796034189382757 p # digits 24
Runtime (s) = 0.676000


Partial factorization of the Twelfth Fermat Number 2^4096+1
# digits 1234
114689 p # digits 6
26017793 p # digits 8
63766529 p # digits 8
190274191361 p # digits 12
Runtime (s) = 1532.878000