Category: Handbook of Applied Cryptography
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:
- Module-Lattice-Based Key-Encapsulation Mechanism Standard
- Number-theoretic transform (integer DFT)
- 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