Blog Entry © Friday, February 27, 2026, by James Pate Williams, Jr., C Pseudorandom Bit Generators and Four Statistical Tests

Blog Entry (c) Monday, February 24, 2026, by James Pate Williams, Jr. TDES Verification

I wrote my Triple-DES C source code a number of years ago. Today, I verified my Cipher Block Chaining version using the NIST online reference document:

CBC-TDES (Encryption)

Key1 is
01234567 89ABCDEF
Key2 is
23456789 ABCDEF01
Key3 is
456789AB CDEF0123
IV is
F69F2445 DF4F9B17

Block #1
Plaintext 6BC1BEE2 2E409F96
InputBlock 9D5E9AA7 F10F0481
OutputBlock 2079C3D5 3AA763E1
Ciphertext 2079C3D5 3AA763E1

Block #2
Plaintext E93D7E11 7393172A
InputBlock C944BDC4 493474CB
OutputBlock 93B79E25 69AB5262
Ciphertext 93B79E25 69AB5262

Block #3
Plaintext AE2D8A57 1E03AC9C
InputBlock 3D9A1472 77A8FEFE
OutputBlock 51657048 1F25B50F
Ciphertext 51657048 1F25B50F

Block #4
Plaintext 9EB76FAC 45AF8E51
InputBlock CFD21FE4 5A8A3B5E
OutputBlock 73C0BDA8 5C8E0DA7
Ciphertext 73C0BDA8 5C8E0DA7

CBC-TDES (Decryption)

Key1 is
01234567 89ABCDEF
Key2 is
23456789 ABCDEF01
Key3 is
456789AB CDEF0123
IV is
F69F2445 DF4F9B17

Block #1
Ciphertext 2079C3D5 3AA763E1
InputBlock 2079C3D5 3AA763E1
OutputBlock 9D5E9AA7 F10F0481
Plaintext 6BC1BEE2 2E409F96
Block #2
Ciphertext 93B79E25 69AB5262
InputBlock 93B79E25 69AB5262
OutputBlock C944BDC4 493474CB
Plaintext E93D7E11 7393172A
Block #3
Ciphertext 51657048 1F25B50F
InputBlock 51657048 1F25B50F
OutputBlock 3D9A1472 77A8FEFE
Plaintext AE2D8A57 1E03AC9C
Block #4
Ciphertext 73C0BDA8 5C8E0DA7
InputBlock 73C0BDA8 5C8E0DA7
OutputBlock CFD21FE4 5A8A3B5E
Plaintext 9EB76FAC 45AF8E51

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

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