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 . . .

Results from Multiple Precision Integer Multiplication Algorithms (c) Sunday, February 15, 2026, by James Pate Williams, Jr. Using Professor Emeritus Arjen K. Lenstra’s Large Integer Package (lip)

The following results illustrate the author’s and Professor Emeritus Arjen K. Lenstra’s multiplication algorithms. The methods in alphabetical order are:
1. Bodrato’s modification of the Toom-Cook multiplication technique
2. Lenstra’s large integer package (lip) built-in multiple precision method
3. Long multiplication from pseudocode in Wikipedia
4. Toom-Cook method from Cook’s 1966 PhD thesis
References:
1. Papers by Marco Bodrato
2. Multiplication - Wikipedia
3. cr.yp.to/bib/1966/cook.html
== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 4
Enter b = 2147483647
Enter M = 1234567890
Enter N = 1234567890
Number of repetitions = 1
M = 971334442946674600221231647138533765049334517138898208814432641876416006\
400115736571
N = 971334442946674600221231647138533765049334517138898208814432641876416006\
400115736571
Toom-Cook Multiplication
Average Runtime = 0.000074200
Over 1 Repetitions
MN = 943490600054526654019119035756125944918077526277676439897594263047388314\
836233229704805255157650098574056832103475286502442743200967269892687335\
748700513503753866838041
== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 2
Enter b = 2147483647
Enter M = 1234567890
Enter N = 1234567890
Number of repetitions = 1
M = 971334442946674600221231647138533765049334517138898208814432641876416006\
400115736571
N = 971334442946674600221231647138533765049334517138898208814432641876416006\
400115736571
Lenstra lip Multiplication
Average Runtime = 0.000007400
Over 1 Repetitions
MN = 943490600054526654019119035756125944918077526277676439897594263047388314\
836233229704805255157650098574056832103475286502442743200967269892687335\
748700513503753866838041
== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 4
Enter b = 2147483647
Enter M = 12345678901234567890
Enter N = 12345678901234567890
Number of repetitions = 1
M = 2026130632828332098161978694183179835926961551850814936441274855035774\
533901237908301792067190081080660611853406806309172584227706257836105490\
238900767068890331810595558979010550
N = 2026130632828332098161978694183179835926961551850814936441274855035774\
533901237908301792067190081080660611853406806309172584227706257836105490\
238900767068890331810595558979010550
Toom-Cook Multiplication
Average Runtime = 0.000098600
Over 1 Repetitions
MN = 41052053412853374997957659248772276766670464267610246450081646198672053\
134774107322853407211671548238594780193988795119754495077504801036773948\
450621659941905079488598768958918884281745778245753016460241195698241515\
318663783334584789872121452838087229440437832037084270117697010189272087\
88688141014237093579164596571668979636977920478671088735457011302500
== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 2
Enter b = 2147483647
Enter M = 12345678901234567890
Enter N = 12345678901234567890
Number of repetitions = 1
M = 2026130632828332098161978694183179835926961551850814936441274855035774\
533901237908301792067190081080660611853406806309172584227706257836105490\
238900767068890331810595558979010550
N = 2026130632828332098161978694183179835926961551850814936441274855035774\
533901237908301792067190081080660611853406806309172584227706257836105490\
238900767068890331810595558979010550
Lenstra lip Multiplication
Average Runtime = 0.000009300
Over 1 Repetitions
MN = 41052053412853374997957659248772276766670464267610246450081646198672053\
134774107322853407211671548238594780193988795119754495077504801036773948\
450621659941905079488598768958918884281745778245753016460241195698241515\
318663783334584789872121452838087229440437832037084270117697010189272087\
88688141014237093579164596571668979636977920478671088735457011302500
== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 5

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

== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 4
Enter b = 2147483647
Enter M = 123456789012345678901234567890
Enter N = 123456789012345678901234567890
Number of repetitions = 1
M = 42263561959479590219289335715252528051946761885385061954793363463431018\
850749052611816045464227557359947957390833136631219765211655242009436305\
106409335048399270235917319942885139182317225885422762482775210395122870\
45968780928724406323190056412004806954312198921740353521
N = 42263561959479590219289335715252528051946761885385061954793363463431018\
850749052611816045464227557359947957390833136631219765211655242009436305\
106409335048399270235917319942885139182317225885422762482775210395122870\
45968780928724406323190056412004806954312198921740353521
Toom-Cook Multiplication
Average Runtime = 0.000183000
Over 1 Repetitions
MN = 1786208669502770299576960480677491594428843761318376718810830214483008\
522779876058101551852828273108216537734660930558577510542169332383202300\
806637802232078747108185518603023831159502647581878153273000030245312879\
938941795477296487228094659168732765010051027312450437648026306828037634\
862435594225658630177203603798218997466111668748532465924932822495598422\
823492688498989692318248236025719132743625324592268073825418742555965769\
253184917848571722561153588394570162730241248387724570796710835550233766\
6905434432429374209450377625018057097441
== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 2
Enter b = 2147483647
Enter M = 123456789012345678901234567890
Enter N = 123456789012345678901234567890
Number of repetitions = 1
M = 42263561959479590219289335715252528051946761885385061954793363463431018\
850749052611816045464227557359947957390833136631219765211655242009436305\
106409335048399270235917319942885139182317225885422762482775210395122870\
45968780928724406323190056412004806954312198921740353521
N = 42263561959479590219289335715252528051946761885385061954793363463431018\
850749052611816045464227557359947957390833136631219765211655242009436305\
106409335048399270235917319942885139182317225885422762482775210395122870\
45968780928724406323190056412004806954312198921740353521
Lenstra lip Multiplication
Average Runtime = 0.000058300
Over 1 Repetitions
MN = 1786208669502770299576960480677491594428843761318376718810830214483008\
522779876058101551852828273108216537734660930558577510542169332383202300\
806637802232078747108185518603023831159502647581878153273000030245312879\
938941795477296487228094659168732765010051027312450437648026306828037634\
862435594225658630177203603798218997466111668748532465924932822495598422\
823492688498989692318248236025719132743625324592268073825418742555965769\
253184917848571722561153588394570162730241248387724570796710835550233766\
6905434432429374209450377625018057097441
== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 5

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

== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 4
Enter b = 1000000000000000000000000000000
Enter M = 123456789012345678901234567890
Enter N = 123456789012345678901234567890
Number of repetitions = 1
M = 10000000000000000000000000000020000000000000000000000000000030000000000\
000000000000000000040000000000000000000000000000050000000000000000000000\
000000060000000000000000000000000000070000000000000000000000000000080000\
000000000000000000000000090000000000000000000000000000000000000000000000\
000000000000010000000000000000000000000000020000000000000000000000000000\
030000000000000000000000000000040000000000000000000000000000050000000000\
000000000000000000060000000000000000000000000000070000000000000000000000\
000000080000000000000000000000000000090000000000000000000000000000000000\
000000000000000000000000010000000000000000000000000000020000000000000000\
000000000000030000000000000000000000000000040000000000000000000000000000\
050000000000000000000000000000060000000000000000000000000000070000000000\
000000000000000000080000000000000000000000000000090000000000000000000000\
00000000
N = 10000000000000000000000000000020000000000000000000000000000030000000000\
000000000000000000040000000000000000000000000000050000000000000000000000\
000000060000000000000000000000000000070000000000000000000000000000080000\
000000000000000000000000090000000000000000000000000000000000000000000000\
000000000000010000000000000000000000000000020000000000000000000000000000\
030000000000000000000000000000040000000000000000000000000000050000000000\
000000000000000000060000000000000000000000000000070000000000000000000000\
000000080000000000000000000000000000090000000000000000000000000000000000\
000000000000000000000000010000000000000000000000000000020000000000000000\
000000000000030000000000000000000000000000040000000000000000000000000000\
050000000000000000000000000000060000000000000000000000000000070000000000\
000000000000000000080000000000000000000000000000090000000000000000000000\
00000000
Toom-Cook Multiplication
Average Runtime = 0.000399800
Over 1 Repetitions
MN = 100000000000000000000000000000400000000000000000000000000001000000000\
000000000000000000002000000000000000000000000000003500000000000000000000\
000000005600000000000000000000000000008400000000000000000000000000012000\
000000000000000000000000016500000000000000000000000000020000000000000000\
000000000000022600000000000000000000000000024400000000000000000000000000\
025500000000000000000000000000026000000000000000000000000000026000000000\
000000000000000000025600000000000000000000000000024900000000000000000000\
000000024000000000000000000000000000033000000000000000000000000000040000\
000000000000000000000000045100000000000000000000000000048400000000000000\
000000000000050000000000000000000000000000050000000000000000000000000000\
048500000000000000000000000000045600000000000000000000000000041400000000\
000000000000000000036000000000000000000000000000049500000000000000000000\
000000060000000000000000000000000000067400000000000000000000000000071600\
000000000000000000000000072500000000000000000000000000070000000000000000\
000000000000064000000000000000000000000000054400000000000000000000000000\
041100000000000000000000000000024000000000000000000000000000033000000000\
000000000000000000040000000000000000000000000000044900000000000000000000\
000000047600000000000000000000000000048000000000000000000000000000046000\
000000000000000000000000041500000000000000000000000000034400000000000000\
000000000000024600000000000000000000000000012000000000000000000000000000\
016500000000000000000000000000020000000000000000000000000000022400000000\
000000000000000000023600000000000000000000000000023500000000000000000000\
000000022000000000000000000000000000019000000000000000000000000000014400\
000000000000000000000000008100000000000000000000000000000000000000000000\
0000000000000000
== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 2
Enter b = 1000000000000000000000000000000
Enter M = 123456789012345678901234567890
Enter N = 123456789012345678901234567890
Number of repetitions = 1
M = 10000000000000000000000000000020000000000000000000000000000030000000000\
000000000000000000040000000000000000000000000000050000000000000000000000\
000000060000000000000000000000000000070000000000000000000000000000080000\
000000000000000000000000090000000000000000000000000000000000000000000000\
000000000000010000000000000000000000000000020000000000000000000000000000\
030000000000000000000000000000040000000000000000000000000000050000000000\
000000000000000000060000000000000000000000000000070000000000000000000000\
000000080000000000000000000000000000090000000000000000000000000000000000\
000000000000000000000000010000000000000000000000000000020000000000000000\
000000000000030000000000000000000000000000040000000000000000000000000000\
050000000000000000000000000000060000000000000000000000000000070000000000\
000000000000000000080000000000000000000000000000090000000000000000000000\
00000000
N = 10000000000000000000000000000020000000000000000000000000000030000000000\
000000000000000000040000000000000000000000000000050000000000000000000000\
000000060000000000000000000000000000070000000000000000000000000000080000\
000000000000000000000000090000000000000000000000000000000000000000000000\
000000000000010000000000000000000000000000020000000000000000000000000000\
030000000000000000000000000000040000000000000000000000000000050000000000\
000000000000000000060000000000000000000000000000070000000000000000000000\
000000080000000000000000000000000000090000000000000000000000000000000000\
000000000000000000000000010000000000000000000000000000020000000000000000\
000000000000030000000000000000000000000000040000000000000000000000000000\
050000000000000000000000000000060000000000000000000000000000070000000000\
000000000000000000080000000000000000000000000000090000000000000000000000\
00000000
Lenstra lip Multiplication
Average Runtime = 0.000076500
Over 1 Repetitions
MN = 100000000000000000000000000000400000000000000000000000000001000000000\
000000000000000000002000000000000000000000000000003500000000000000000000\
000000005600000000000000000000000000008400000000000000000000000000012000\
000000000000000000000000016500000000000000000000000000020000000000000000\
000000000000022600000000000000000000000000024400000000000000000000000000\
025500000000000000000000000000026000000000000000000000000000026000000000\
000000000000000000025600000000000000000000000000024900000000000000000000\
000000024000000000000000000000000000033000000000000000000000000000040000\
000000000000000000000000045100000000000000000000000000048400000000000000\
000000000000050000000000000000000000000000050000000000000000000000000000\
048500000000000000000000000000045600000000000000000000000000041400000000\
000000000000000000036000000000000000000000000000049500000000000000000000\
000000060000000000000000000000000000067400000000000000000000000000071600\
000000000000000000000000072500000000000000000000000000070000000000000000\
000000000000064000000000000000000000000000054400000000000000000000000000\
041100000000000000000000000000024000000000000000000000000000033000000000\
000000000000000000040000000000000000000000000000044900000000000000000000\
000000047600000000000000000000000000048000000000000000000000000000046000\
000000000000000000000000041500000000000000000000000000034400000000000000\
000000000000024600000000000000000000000000012000000000000000000000000000\
016500000000000000000000000000020000000000000000000000000000022400000000\
000000000000000000023600000000000000000000000000023500000000000000000000\
000000022000000000000000000000000000019000000000000000000000000000014400\
000000000000000000000000008100000000000000000000000000000000000000000000\
0000000000000000
== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 5

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

== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 1
Enter e in 10^e = 50
b = 100000000000000000000000000000000000000000000000000
Enter U = 12345678901234567890123456789012345678901234567890
Enter V = 12345678901234567890123456789012345678901234567890
Enter R = 1
Bodrato Multiplication
Average Runtime = 0.005534500
Over 1 Repetitions
W = 15241578753238836750495351562566681945008382873375704923650053345576253\
6198787501905199875019052100
== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 2
Enter b = 10
Enter M = 12345678901234567890123456789012345678901234567890
Enter N = 12345678901234567890123456789012345678901234567890
Number of repetitions = 1
M = 12345678901234567890123456789012345678901234567890
N = 12345678901234567890123456789012345678901234567890
Lenstra lip Multiplication
Average Runtime = 0.000005700
Over 1 Repetitions
MN = 15241578753238836750495351562566681945008382873375704923650053345576253\
6198787501905199875019052100
== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 3
Enter b = 100000000000000000000000000000000000000000000000000
Enter A = 12345678901234567890123456789012345678901234567890
Enter B = 12345678901234567890123456789012345678901234567890
Enter # = 1
Long Multiplication
Average Runtime = 0.000029500
Over 1 Repetitions
x = 15241578753238836750495351562566681945008382873375704923650053345576253\
6198787501905199875019052100
== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 4
Enter b = 10
Enter M = 12345678901234567890123456789012345678901234567890
Enter N = 12345678901234567890123456789012345678901234567890
Number of repetitions = 1
M = 12345678901234567890123456789012345678901234567890
N = 12345678901234567890123456789012345678901234567890
Toom-Cook Multiplication
Average Runtime = 0.000278200
Over 1 Repetitions
MN = 15241578753238836750495351562566681945008382873375704923650053345576253\
6198787501905199875019052100
== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 5

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

== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 1
Enter e in 10^e = 100
b = 100000000000000000000000000000000000000000000000000000000000000000000\
00000000000000000000000000000000
Enter U = 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
Enter V = 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
Enter R = 1
Bodrato Multiplication
Average Runtime = 0.007581100
Over 1 Repetitions
W = 15241578753238836750495351562566681945008382873376009755225118122311263\
526910001524158887669562677515622630876390795200121932731260478594250876\
39153757049236500533455762536198787501905199875019052100
== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 2
Enter b = 10
Enter M = 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
Enter N = 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
Number of repetitions = 1
M = 123456789012345678901234567890123456789012345678901234567890123456789012\
3456789012345678901234567890
N = 123456789012345678901234567890123456789012345678901234567890123456789012\
3456789012345678901234567890
Lenstra lip Multiplication
Average Runtime = 0.000004300
Over 1 Repetitions
MN = 15241578753238836750495351562566681945008382873376009755225118122311263\
526910001524158887669562677515622630876390795200121932731260478594250876\
39153757049236500533455762536198787501905199875019052100
== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 3
Enter b = 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Enter A = 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
Enter B = 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
Enter # = 1
Long Multiplication
Average Runtime = 0.000070000
Over 1 Repetitions
x = 15241578753238836750495351562566681945008382873376009755225118122311263\
526910001524158887669562677515622630876390795200121932731260478594250876\
39153757049236500533455762536198787501905199875019052100
== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 4
Enter b = 10
Enter M = 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
Enter N = 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
Number of repetitions = 1
M = 123456789012345678901234567890123456789012345678901234567890123456789012\
3456789012345678901234567890
N = 123456789012345678901234567890123456789012345678901234567890123456789012\
3456789012345678901234567890
Toom-Cook Multiplication
Average Runtime = 0.000396200
Over 1 Repetitions
MN = 15241578753238836750495351562566681945008382873376009755225118122311263\
526910001524158887669562677515622630876390795200121932731260478594250876\
39153757049236500533455762536198787501905199875019052100
== Menu ==
1 Bodrato Multiplication
2 Lenstra lip Multiplication
3 Long Multiplication
4 Toom-Cook Algorithm
5 Exit
Option (1 - 5) = 5

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

References:

  1. Papers by Marco Bodrato
  2. Multiplication – Wikipedia
  3. cr.yp.to/bib/1966/cook.html

Blog Entry © Thursday, February 5, 2026, by James Pate Williams, Jr., Three Toom-Cook 3-Way Multiplication Implementations

I translated some of Marco Bodrato ‘s pseudocode found on his website:

Optimal Toom-Cook Polynomial Multiplication, by Marco Bodrato

To Microsoft Win32 C++. I used Microsoft’s Visual Studio 2022 Community Version.

Balanced Toom-Cook 3-Way Multiplication

U = 7

V = 8

W = 56

U = 9

V = 9

W = 81

U = 18

V = 17

W = 306

U = 123

V = 456

W = 56088

U = 1234

V = 5678

W = 7006652

U = 12345

V = 67890

W = 838102050

U = 123456

V = 789012

W = 97408265472

D:\ToomCookBodrato\x64\Debug\ToomCookBodrato.exe (process 30392) exited with code 0 (0x0).

Unbalanced Toom-Cook 3-Way Multiplication

U = 20

V = 5

W = 100

U = 112

V = 20

W = 2240

U = 1234

V = 567

W = 699678

U = 12345

V = 6789

W = 83810205

U = 123456

V = 78901

W = 9740801856

U = 1234567

V = 890123

W = 1098916481741

U = 12345678

V = 9012345

W = 111263509394910

D:\ToomCookBodrato\x64\Debug\ToomCookBodrato.exe (process 13108) exited with code 0 (0x0).

Asymmetrical Squaring, Splitting in Five

U = 8

W = 64

U = 12

W = 144

U = 321

W = 103041

U = 1234

W = 1522756

U = 54321

W = 2950771041

U = 123456

W = 15241383936

D:\ToomCookBodrato\x64\Debug\ToomCookBodrato.exe (process 27592) exited with code 0 (0x0).

Press any key to close this window . . .

The accompanying source code is released under the GNU General Public License, version 3. The full license text is included in the downloadable archive and is also available at:
https://www.gnu.org/licenses/gpl-3.0.html

/*
   Toom–Cook Multiplication (Bodrato-inspired implementation)
   Copyright (C) 2026 James Pate Williams, Jr.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

#pragma once

// Algorithm structure inspired by Marco Bodrato’s Toom–Cook notes.
// See: http://www.bodrato.it/toom-cook/
// All implementation code and comments in this file are by
// James Pate Williams, Jr., BA, BS, Master of Software Engineering,
// Doctor of Philosophy in Computer Science

class Multiplication
{

public:

	static long long BalancedToomCook3Way(
		long long b, long long U, long long V);
	static long long UnbalancedToomCook3Way(
		long long b, long long U, long long V);
	static long long AsymeticalSquaring(
		long long b, long long U);
};

/*
   Toom–Cook Multiplication (Bodrato-inspired implementation)
   Copyright (C) 2026 James Pate Williams, Jr.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

#include "pch.h"
#include "Multiplication.h"

static void BaseBDigits(
	long long B, long long u,
	std::vector<long long>& digits)
{
	while (u > 0)
	{
		long long d = u % B;
		u = u / B;
		digits.push_back(d);
	}
}

long long Multiplication::BalancedToomCook3Way(
	long long b, long long U, long long V)
{
	double k = 3.0;
	double logU = log(U) / log(b);
	double logV = log(V) / log(b);
	double floorU = floor(floor(logU) / k);
	double floorV = floor(floor(logV) / k);
	double i = fmax(floorU, floorV) + 1.0;
	long long B = static_cast<long long>(pow(b, i));
	long long W = 0;
	std::vector<long long> UDigits;
	std::vector<long long> VDigits;

	for (long long j = 0; j < 5; j++)
	{
		long long x = 0, y = 0;

		if (j == 0)
			x = 1;
		else if (j == 1)
			x = -2;
		else if (j == 2)
			x = 1;
		else if (j == 3)
			x = -1;
		else
			x = 1;

		if (j == 0)
			y = 1;
		else if (j == 1)
			y = 1;
		else if (j == 2)
			y = 1;
		else if (j == 3)
			y = 1;
		else
			y = 0;

		UDigits.clear();
		VDigits.clear();

		BaseBDigits(B, U, UDigits);
		BaseBDigits(B, V, VDigits);

		long long U0 = 0, U1 = 0, U2 = 0;
		long long V0 = 0, V1 = 0, V2 = 0;

		if (UDigits.size() == 3)
		{
			U2 = UDigits[2];
			U1 = UDigits[1];
			U0 = UDigits[0];
		}

		if (VDigits.size() == 3)
		{
			V2 = VDigits[2];
			V1 = VDigits[1];
			V0 = VDigits[0];
		}

		if (UDigits.size() == 2)
		{
			U2 = 0;
			U1 = UDigits[1];
			U2 = UDigits[0];
		}

		if (VDigits.size() == 2)
		{
			V2 = 0;
			V1 = VDigits[1];
			V0 = VDigits[0];
		}

		if (UDigits.size() == 1)
		{
			U2 = 0;
			U1 = 0;
			U0 = UDigits[0];
		}

		if (VDigits.size() == 1)
		{
			V2 = 0;
			V1 = 0;
			V0 = VDigits[0];
		}

		if (UDigits.size() == 0 ||
			VDigits.size() == 0)
			break;

		long long x2 = x * x;
		long long y2 = y * y;
		long long xy = x * y;
		
		U = U2 * x2 + U1 * xy + U0 * y2;
		V = V2 * x2 + V1 * xy + V0 * y2;
		
		if (U == 0 || V == 0)
			break;

		long long W3 = U0 + U2;
		long long W2 = V0 + V2;
		long long W0 = W3 - U1;
		long long W4 = W2 - V1;
		
		W3 = W3 + U1;
		W2 = W2 + V1;

		long long W1 = W3 * W2;

		W2 = W0 * W4;
		W0 = ((W0 + U2) << 1) - U0;
		W4 = ((W4 + V2) << 1) - V0;
		W3 = W0 * W4;
		W0 = U0 * V0;
		W4 = U2 * V2;

		W3 = (W3 - W1) / k;
		W1 = (W1 - W2) >> 1;
		W2 = W2 - W0;
		W3 = ((W2 - W3) >> 1) + (W4 << 1);
		W2 = W2 + W1;

		W3 = W4 * x + W3 * y;
		W1 = W2 * x + W1 * y;
		W1 = W1 - W3;

		W = W3 * x * x2 + W1 * x * y2 + W0 * y2 * y2;
	}

	return W;
}

long long Multiplication::UnbalancedToomCook3Way(
	long long b, long long U, long long V)
{
	double k = 3.0;
	double logU = log(U) / log(b);
	double logV = log(V) / log(b);
	double floorU = floor(floor(logU) / k);
	double floorV = floor(floor(logV) / k);
	double i = fmax(floorU, floorV) + 1.0;
	long long B = static_cast<long long>(pow(b, i));
	long long W = 0;
	std::vector<long long> UDigits;
	std::vector<long long> VDigits;

	for (long long j = 0; j < 5; j++)
	{
		long long x = 0, y = 0;

		if (j == 0)
			x = 1;
		else if (j == 1)
			x = -2;
		else if (j == 2)
			x = 1;
		else if (j == 3)
			x = -1;
		else
			x = 1;

		if (j == 0)
			y = 1;
		else if (j == 1)
			y = 1;
		else if (j == 2)
			y = 1;
		else if (j == 3)
			y = 1;
		else
			y = 0;

		long long U0 = 0, U1 = 0, U2 = 0;
		long long V0 = 0, V1 = 0, V2 = 0;
		long long U3 = 0;
		long long x2 = x * x, y2 = y * y;
		long long x3 = x * x2, y3 = y * y2;

		UDigits.clear();
		VDigits.clear();

		BaseBDigits(B, U, UDigits);
		BaseBDigits(B, V, VDigits);

		if (UDigits.size() == 4)
		{
			U3 = UDigits[3];
			U2 = UDigits[2];
			U1 = UDigits[1];
			U0 = UDigits[0];
		}

		if (UDigits.size() == 3)
		{
			U3 = 0;
			U2 = UDigits[2];
			U1 = UDigits[1];
			U0 = UDigits[0];
		}

		if (VDigits.size() == 3)
		{
			V2 = VDigits[2];
			V1 = VDigits[1];
			V0 = VDigits[0];
		}

		if (UDigits.size() == 2)
		{
			U3 = 0;
			U2 = 0;
			U1 = UDigits[1];
			U0 = UDigits[0];
		}

		if (VDigits.size() == 2)
		{
			V2 = 0;
			V1 = VDigits[1];
			V0 = VDigits[0];
		}

		if (UDigits.size() == 1)
		{
			U3 = 0;
			U2 = 0;
			U1 = 0;
			U0 = UDigits[0];
		}

		if (VDigits.size() == 1)
		{
			V2 = 0;
			V1 = 0;
			V0 = VDigits[0];
		}

		if (UDigits.size() == 0 ||
			VDigits.size() == 0)
			break;

		U = U3 * x3 + U2 * x2 * y + U1 * x * y2 + U0 * y3;
		V = V1 * x + V0 * y;

		if (U == 0 || V == 0)
			break;

		long long W3 = U0 + U2;
		long long W2 = V0 + V1;
		long long W1 = U1 + U3;
		long long W4 = V0 - V1;
		long long W0 = W3 - W1;
		
		W3 = W3 + W1;
		W1 = W3 * W2;
		W2 = W0 * W4;
		W0 = U0 - (((U1 - ((U2 - U3) << 1)) << 1) << 1);
		W4 = W4 - V1;
		W3 = W0 * W4;
		W0 = U0 * V0;
		W4 = U3 * V1;

		W3 = (W3 - W1) / k;
		W1 = (W1 - W2) >> 1;
		W2 = W2 - W0;
		W3 = ((W2 - W3) >> 1) + (W4 << 1);
		W2 = W2 + W1;

		W3 = W4 * x + W3 * y;
		W1 = W2 * x + W1 * y;
		W1 = W1 - W3;

		W = W3 * x3 + W1 * x * y2 + W0 * y2 * y2;
	}

	return W;
}

long long Multiplication::AsymeticalSquaring(
	long long b, long long U)
{
	double k = 5.0;
	double logU = log(U) / log(b);
	double floorU = floor(floor(logU) / k);
	double i = floorU + 1.0;
	long long B = static_cast<long long>(pow(b, i));
	long long W = 0, Wp = 0;
	std::vector<long long> UDigits;

	for (long long j = 0; j < 9; j++)
	{
		long long x = 0;

		if (j == 0)
			x = 0;
		else if (j == 1)
			x = 0;
		else if (j == 2)
			x = -1;
		else if (j == 3)
			x = 1;
		else if (j == 4 || j == 5 || j == 6)
			continue;
		else if (j == 7 || j == 8)
			x = 1;

		UDigits.clear();
		BaseBDigits(B, U, UDigits);
		
		long long x2 = x * x, x3 = x * x2, x4 = x2 * x2;
		long long U0 = 0, U1 = 0, U2 = 0, U3 = 0, U4 = 0;

		if (UDigits.size() == 5)
		{
			U4 = UDigits[4];
			U3 = UDigits[3];
			U2 = UDigits[2];
			U1 = UDigits[1];
			U0 = UDigits[0];
		}

		if (UDigits.size() == 4)
		{
			U4 = 0;
			U3 = UDigits[3];
			U2 = UDigits[2];
			U1 = UDigits[1];
			U0 = UDigits[0];
		}

		if (UDigits.size() == 3)
		{
			U4 = 0;
			U3 = 0;
			U2 = UDigits[2];
			U1 = UDigits[1];
			U0 = UDigits[0];
		}

		if (UDigits.size() == 2)
		{
			U4 = 0;
			U3 = 0;
			U2 = 0;
			U1 = UDigits[1];
			U0 = UDigits[0];
		}

		if (UDigits.size() == 1)
		{
			U4 = 0;
			U3 = 0;
			U2 = 0;
			U1 = 0;
			U0 = UDigits[0];
		}

		U = U4 * x4 + U3 * x3 + U2 * x2 + U1 * x + U0;

		long long W0 = U0 - U3;
		long long W1 = U3 - U1;
		long long W6 = U1 - U2;
		long long W4 = U1 + U2;
		long long W5 = W6 - U4;
		long long W3 = W5 + (W0 << 1);
		W0 = W0 - W5;
		W6 = W0 + (W6 << 1);
		long long W7 = W6 + W1;
		W5 = W7 + W1;
		long long W8 = W5 + (W4 << 1);
		W4 = W4 - U4;

		long long W2 = (W4) * (W3);
		W4 = (W6) * (W5);
		W3 = (W7) * (W1);
		W1 = U0 * U1 * 2;
		W7 = U3 * U4 * 2;
		W5 = (W8) * (W8); W6 = (W0) * (W0);
		W0 = U0 * U0;
		W8 = U4 * U4;

		W2 = (W4) * (W3);
		W4 = (W6) * (W5);
		W3 = (W7) * (W1);
		W1 = U0 * U1 * 2;
		W7 = U3 * U4 * 2;
		W5 = (W8) * (W8);
		W6 = (W0) * (W0);
		W0 = U0 * U0;
		W8 = U4 * U4;

		W6 = (W6 + W5) >> 1;
		W5 = W5 - W6;
		W4 = (W4 + W6) >> 1;
		W3 = W3 + (W5 >> 1);
		W6 = W6 - W4;
		W5 = W5 - W3 - W1;
		W4 = W4 - W8 - W0;
		W3 = W3 - W7;
		W2 = W2 - W8 - W1 - W7 + W4 + W5;
		W6 = W6 - W2;

		W = W8 * x4 * x4 + W7 * x3 * x4 + W6 * x3 * x3 +
			W5 * x * x4 + W4 * x4 + W3 * x3 + W2 * x2 + W1 * x + W0;
		
		if (W != 0)
			Wp = W;

		if (Wp != 0)
			break;
	}

	return W;
}

/*
   Toom–Cook Multiplication (Bodrato-inspired implementation)
   Copyright (C) 2026 James Pate Williams, Jr.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

#include "pch.h"
#include <iostream>
#include "Multiplication.h"

int main()
{
    bool balanced = false, square = true;

    if (balanced && !square)
    {
        long long U = 7;
        long long V = 8;
        long long W = 0;
        // W = U * V = 56
        W = Multiplication::BalancedToomCook3Way(10, U, V);
        std::cout << "U = " << U << std::endl;
        std::cout << "V = " << V << std::endl;
        std::cout << "W = " << W << std::endl;
        U = 9;
        V = 9;
        W = Multiplication::BalancedToomCook3Way(10, U, V);
        // W = U * V = 81
        std::cout << "U = " << U << std::endl;
        std::cout << "V = " << V << std::endl;
        std::cout << "W = " << W << std::endl;
        U = 18;
        V = 17;
        W = Multiplication::BalancedToomCook3Way(100, U, V);
        std::cout << "U = " << U << std::endl;
        std::cout << "V = " << V << std::endl;
        std::cout << "W = " << W << std::endl;
        // W = U * V = 306
        U = 123;
        V = 456;
        W = Multiplication::BalancedToomCook3Way(1000, U, V);
        std::cout << "U = " << U << std::endl;
        std::cout << "V = " << V << std::endl;
        std::cout << "W = " << W << std::endl;
        // W = U * V = 56,088
        U = 1234;
        V = 5678;
        W = Multiplication::BalancedToomCook3Way(10000, U, V);
        std::cout << "U = " << U << std::endl;
        std::cout << "V = " << V << std::endl;
        std::cout << "W = " << W << std::endl;
        // W = U * V = 7,006,652
        U = 12345;
        V = 67890;
        W = Multiplication::BalancedToomCook3Way(100000, U, V);
        std::cout << "U = " << U << std::endl;
        std::cout << "V = " << V << std::endl;
        std::cout << "W = " << W << std::endl;
        // W = U * V = 838,102,050
        U = 123456;
        V = 789012;
        W = Multiplication::BalancedToomCook3Way(1000000, U, V);
        std::cout << "U = " << U << std::endl;
        std::cout << "V = " << V << std::endl;
        std::cout << "W = " << W << std::endl;
        // W = U * V = 838,102,050
    }

    else if (!balanced && !square)
    {
        long long U = 20;
        long long V = 5;
        long long W;
        // W = U * V = 100
        W = Multiplication::UnbalancedToomCook3Way(100, U, V);
        std::cout << "U = " << U << std::endl;
        std::cout << "V = " << V << std::endl;
        std::cout << "W = " << W << std::endl;
        U = 112;
        V = 20;
        W = Multiplication::UnbalancedToomCook3Way(1000, U, V);
        // W = U * V = 2240
        std::cout << "U = " << U << std::endl;
        std::cout << "V = " << V << std::endl;
        std::cout << "W = " << W << std::endl;
        U = 1234;
        V = 567;
        W = Multiplication::UnbalancedToomCook3Way(10000, U, V);
        std::cout << "U = " << U << std::endl;
        std::cout << "V = " << V << std::endl;
        std::cout << "W = " << W << std::endl;
        // W = U * V = 699,678
        U = 12345;
        V = 6789;
        W = Multiplication::UnbalancedToomCook3Way(100000, U, V);
        std::cout << "U = " << U << std::endl;
        std::cout << "V = " << V << std::endl;
        std::cout << "W = " << W << std::endl;
        // W = U * V = 83,810,205
        U = 123456;
        V = 78901;
        W = Multiplication::UnbalancedToomCook3Way(1000000, U, V);
        std::cout << "U = " << U << std::endl;
        std::cout << "V = " << V << std::endl;
        std::cout << "W = " << W << std::endl;
        // W = U * V = 97,408,265,472
        U = 1234567;
        V = 890123;
        W = Multiplication::UnbalancedToomCook3Way(10000000, U, V);
        std::cout << "U = " << U << std::endl;
        std::cout << "V = " << V << std::endl;
        std::cout << "W = " << W << std::endl;
        // W = U * V = 9,740,885,481,741
        U = 12345678;
        V = 9012345;
        W = Multiplication::UnbalancedToomCook3Way(100000000, U, V);
        std::cout << "U = " << U << std::endl;
        std::cout << "V = " << V << std::endl;
        std::cout << "W = " << W << std::endl;
        // W = U * V = 111,263,509,394,910
    }

    else if (square)
    {
        long long U = 8;
        long long W = Multiplication::AsymeticalSquaring(10, U);
        std::cout << "U = " << U << std::endl;
        std::cout << "W = " << W << std::endl;
        U = 12;
        W = Multiplication::AsymeticalSquaring(100, U);
        std::cout << "U = " << U << std::endl;
        std::cout << "W = " << W << std::endl;
        U = 321;
        W = Multiplication::AsymeticalSquaring(1000, U);
        std::cout << "U = " << U << std::endl;
        std::cout << "W = " << W << std::endl;
        U = 1234;
        W = Multiplication::AsymeticalSquaring(10000, U);
        std::cout << "U = " << U << std::endl;
        std::cout << "W = " << W << std::endl;
        U = 54321;
        W = Multiplication::AsymeticalSquaring(100000, U);
        std::cout << "U = " << U << std::endl;
        std::cout << "W = " << W << std::endl;
        U = 123456;
        W = Multiplication::AsymeticalSquaring(1000000, U);
        std::cout << "U = " << U << std::endl;
        std::cout << "W = " << W << std::endl;
    }
    return 0;
}

Blog Entry © Wednesday, February 4, 2026, by James Pate Williams, Jr. and the Microsoft Copilot Two Multiplication Algorithms from Wikipedia

[BEGIN COPILOT TEXT]

## Introduction

This small C++ console program implements two classical multiplication algorithms: 

**long multiplication** (the grade‑school method) and **Karatsuba multiplication**, the first sub‑quadratic multiplication algorithm discovered (Anatoly Karatsuba, 1960).

My goal here is not to optimize or modernize the algorithms, but to preserve their structure in a clear, readable form. The implementations follow the versions presented in the Wikipedia “Multiplication” article as faithfully as possible.

The code is intentionally simple and procedural. It uses 1‑based indexing for digit arrays because that mirrors the mathematical notation more closely than 0‑based indexing.

## Long Multiplication

This function implements the classical long multiplication algorithm in an arbitrary base. 

Digits are stored in reverse order (least significant digit first), which simplifies carry propagation.

The implementation below is intentionally direct and mirrors the textbook algorithm step‑by‑step

## Karatsuba Multiplication (Base 10)

This is a minimal, non‑recursive implementation of the Karatsuba method. 

The inputs are split into high and low parts:

x = x_1 * B ^ m + x_0

y = y_1 * B ^ m + y_0

Karatsuba reduces the number of multiplications from 4 to 3 by computing:

z = x * y = z_2 *B ^ 2m + z_1 * B ^ m + z_0

This implementation follows the Wikipedia pseudocode closely.

[END COPILOT TEXT]

#pragma once

class MyAlgorithms
{

public:

	static void LongMultiplication(
		int base, int p, int q, int& pSize,
		std::vector<int> a,
		std::vector<int> b,
		std::vector<int>& product
	);

	static void KaratsubaBase10(
		int x0, int x1, int y0, int y1,
		int B, int m, long long& z);
};
#include "pch.h"
#include "MyAlgorithms.h"

void MyAlgorithms::LongMultiplication(
	int base, int p, int q, int& pSize,
	std::vector<int> a, std::vector<int> b,
	std::vector<int>& product)
{
	pSize = p + q;
	product.resize(pSize + 1LL);

	for (int b_i = 1; b_i <= q; b_i++)
	{
		int carry = 0;

		for (int a_i = 1; a_i <= p; a_i++)
		{
			product[static_cast<long long>(a_i) + b_i - 1LL] +=
				carry + a[a_i] * b[b_i];
			carry = product[static_cast<long long>(a_i) + b_i - 1] / base;
			product[static_cast<long long>(a_i) + b_i - 1] =
				product[static_cast<long long>(a_i) + b_i - 1] % base;
		}

		product[static_cast<long long>(b_i) + p] = carry;
	}
}

void MyAlgorithms::KaratsubaBase10(
	int B, int m, int x0, int x1,
	int y0, int y1, long long& z)
{
	int pb = static_cast<int>(pow(B, m));
	int x = x1 * pb + x0;
	int y = y1 * pb + y0;
	int z2 = x1 * y1;
	int z1 = x1 * y0 + x0 * y1;
	int z0 = x0 * y0;

	z = z2 * static_cast<int>(pow(B, 2 * m)) + z1 * pb + z0;
}

#include "MyAlgorithms.h"

static void DoLongMultiplication()
{
	int base = 0, p = 0, q = 0, pSize = 0;
	char line[128] = "";
	char inputaStr[128] = "";
	char inputbStr[128] = "";
	char* aReverseStr = nullptr;
	char* bReverseStr = nullptr;
	std::cout << "Enter base = ";
	std::cin.getline(line, 128);
	base = atoi(line);
	std::cout << "a = ";
	std::cin.getline(inputaStr, 128);
	std::cout << "b = ";
	std::cin.getline(inputbStr, 128);
	aReverseStr = _strrev(inputaStr);
	bReverseStr = _strrev(inputbStr);
	p = static_cast<int>(strlen(aReverseStr));
	q = static_cast<int>(strlen(bReverseStr));
	pSize = p + q;
	std::vector<int> a(p + 1);
	std::vector<int> b(q + 1);
	std::vector<int> ab(p + q + 1);
	std::vector<int> product;

	for (int i = 1; i <= p; i++)
		a[i] = aReverseStr[i - 1] - '0';

	for (int i = 1; i <= q; i++)
		b[i] = bReverseStr[i - 1] - '0';

	MyAlgorithms::LongMultiplication(
		base, p, q, pSize, a, b, ab);

	size_t i = ab.size() - 1, j = 1;

	while (i >= 0)
	{
		if (ab[i] == 0)
			i--;
		else
			break;
	}

	product.push_back(0);

	for (j = i; j >= 1; j--)
		product.push_back(ab[j]);

	std::cout << "product = ";

	for (int i = 1; i < product.size(); i++)
		std::cout << product[i];

	std::cout << std::endl;
}

static void DoKaratsuba()
{
	char line[128] = "";
	std::cout << "Enter base = ";
	std::cin.getline(line, 128);
	int B = atoi(line);
	std::cout << "Enter m = ";
	std::cin.getline(line, 128);
	int m = atoi(line);
	std::cout << "x1 = ";
	std::cin.getline(line, 128);
	int x1 = atoi(line);
	std::cout << "x0 = ";
	std::cin.getline(line, 128);
	int x0 = atoi(line);
	std::cout << "y1 = ";
	std::cin.getline(line, 128);
	int y1 = atoi(line);
	std::cout << "y0 = ";
	std::cin.getline(line, 128);
	int y0 = atoi(line);
	long long z = 0;
	MyAlgorithms::KaratsubaBase10(
		B, m, x0, x1, y0, y1, z);
	std::cout << "z = " << z << std::endl;
}

int main()
{
	while (true)
	{
		char line[128] = "";
		std::cout << "== Menu ==" << std::endl;
		std::cout << "1 Long Multiplication" << std::endl;
		std::cout << "2 Karatsuba Multiplication" << std::endl;
		std::cout << "3 Exit" << std::endl;
		std::cout << "Option (1 or 2 or 3) = ";
		std::cin.getline(line, 128);
		char option = line[0];

		if (option == '1')
		{
			DoLongMultiplication();
		}

		else if (option == '2')
		{
			DoKaratsuba();
		}

		else
			break;
	}

	return 0;
}

== Menu ==
1 Long Multiplication
2 Karatsuba Multiplication
3 Exit
Option (1 or 2 or 3) = 1
Enter base = 10
a = 506
b = 208
product = 105248
== Menu ==
1 Long Multiplication
2 Karatsuba Multiplication
3 Exit
Option (1 or 2 or 3) = 2
Enter base = 10
Enter m = 2
x1 = 5
x0 = 6
y1 = 2
y0 = 8
z = 105248
== Menu ==
1 Long Multiplication
2 Karatsuba Multiplication
3 Exit
Option (1 or 2 or 3) = 3

D:\Multiplication\x64\Debug\Multiplication.exe (process 30912) exited with code 0 (0x0).
Press any key to close this window . . .

Blog Entry © Sunday, October 26, 2025, by James Pate Williams, Jr. More Factoring with Arjen K. Lenstra’s LIP (Large Integer Package)

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 © Sunday, October 19, 2025, by James Pate Williams, Jr. LIPCalculator (Large Integer Package Calculator)

Blog Entry © Wednesday, October 15, 2025, by James Pate Williams, Jr. Miscellaneous Algorithms from Chapters 2 and 4 of the “Handbook of Applied Cryptography” by Alfred J. Menezes, Paul C. van Oorschot, and Scott A. Vanstone

#pragma once
class PrimalityTests
{

public:

	static int Jacobi(long long a, long long n);

	static void LongLongToBits(
		long long n, std::vector<int>& bits);

	static long long ModPow(
		long long a, long long k, long long n);

	static bool MillerRabin(long long n, int t);

	static bool SolovayStrassen(long long n, int t);
};

#include "pch.h"
#include "PrimalityTests.h"

int PrimalityTests::Jacobi(long long a, long long n) {
	int s;
	long long a1, b = a, e = 0, m, n1;

	if (a == 0)
		return 0;

	if (a == 1)
		return 1;

	while ((b & 1) == 0)
		b >>= 1, e++;

	a1 = b;
	m = n % 8;

	if (!(e & 1))
		s = +1;
	else if (m == 1 || m == 7)
		s = +1;
	else if (m == 3 || m == 5)
		s = -1;

	if (n % 4 == 3 && a1 % 4 == 3)
		s = -s;

	if (a1 != 1)
		n1 = n % a1;
	else
		n1 = 1;

	return s * Jacobi(n1, a1);
}

void PrimalityTests::LongLongToBits(
	long long n, std::vector<int>& bits) {
	bits.clear();

	while (n > 0) {
		int digit = (int)(n % 2);
		bits.push_back(digit);
		n /= 2;
	}
} 

long long PrimalityTests::ModPow(
	long long a, long long k, long long n) {
	std::vector<int> kBits;
	LongLongToBits(k, kBits);

	long long b = 1;

	if (k == 0) {
		return b;
	}

	long long A = a;

	if (kBits[0] == 1) {
		b = a;
	}

	for (int i = 1; i < (int)kBits.size(); i++) {
		A = (A * A) % n;

		if (kBits[i] == 1) {
			b = (A * b) % n;
		}
	}

	return b;
}

bool PrimalityTests::MillerRabin(long long n, int t) {
	if (n == 2 || n == 3) {
		return true;
	}

	long long m = n % 2;

	if (m == 0) {
		return false;
	}

	long long n2 = n - 2;
	std::random_device rd;  // Seed generator
	std::mt19937 mt(rd());  // Mersenne Twister engine
	std::uniform_int_distribution<long long> dist(2, n2);

	long long n1 = n - 1;
	long long r = n1;
	long s = 0;

	m = r % 2;

	while (m == 0) {
		r = r / 2;
		m = r % 2;
		s++;
	}

	for (int i = 1; i <= t; i++) {
		long long a = dist(mt);
		long long y = ModPow(a, r, n);

		if (y != 1 && y != n1) {
			int j = 1;

			while (j <= s && y != n1) {
				y = ModPow(y, 2, n);

				if (y == 1)
					return false;

				j++;
			}

			if (y != n1)
				return false;
		}
	}

	return true;
}

bool PrimalityTests::SolovayStrassen(long long n, int t) {
	long long n1 = n - 1, n2 = n - 2, n12 = n1 / 2;
	std::random_device rd;  // Seed generator
	std::mt19937 mt(rd());  // Mersenne Twister engine
	std::uniform_int_distribution<long long> dist(2, n2);

	for (int i = 1; i <= t; i++) {
		long long a = dist(mt);
		long long r = ModPow(a, n12, n);

		if (r != 1 && r != n1)
			return false;

		int s = Jacobi(a, n);

		if (!(r == s) && !(s == -1 && r == n1))
			return false;
	}

	return true;
}

// ProbPrimalityTests.cpp (c) Monday, October 13, 2025
// Reference: "Handbook of Applied Cryptography" by
// Alfred J. Menezes, Paul C. van Oorschot, Scott A.
// Vanstone Chapters 2, 3, and 4
// https://www.walter-fendt.de/html5/men/primenumbers_en.htm

#include "pch.h"

int main()
{
	while (true) {
		std::string str = "";
		std::cout << "== Menu ==" << std::endl;
		std::cout << "1 Test Jacobi" << std::endl;
		std::cout << "2 Test To Bits" << std::endl;
		std::cout << "3 Test ModPow" << std::endl;
		std::cout << "4 Test Miller-Rabin" << std::endl;
		std::cout << "5 Test Solovay-Strassen" << std::endl;
		std::cout << "6 Exit" << std::endl;
		std::cout << "Option (1 - 6): ";
		std::getline(std::cin, str);
		int option = std::stoi(str);
		if (option < 1 || option > 6) {
			std::cout << "Illegal option" << std::endl;
			continue;
		}
		if (option == 6) {
			break;
		}
		switch (option)	{
		case 1:	{
			std::cout << "a = ";
			std::getline(std::cin, str);
			long long a = std::stoll(str);
			std::cout << "n = ";
			std::getline(std::cin, str);
			long long n = std::stoll(str);
			int j = PrimalityTests::Jacobi(a, n);
			std::cout << "Jacobi = " << j << std::endl;
			break;
		}
		case 2:	{
			std::vector<int> bits = { };
			std::cout << "n = ";
			std::getline(std::cin, str);
			long long n = std::stoll(str);
			PrimalityTests::LongLongToBits(n, bits);
			for (int i = (int)bits.size() - 1; i >= 0; i--) {
				std::cout << bits[i];
			}
			std::cout << std::endl;
			break;
		}
		case 3:	{
			std::cout << "a = ";
			std::getline(std::cin, str);
			long long a = std::stoll(str);
			std::cout << "k = ";
			std::getline(std::cin, str);
			long long k = std::stoll(str);
			std::cout << "n = ";
			std::getline(std::cin, str);
			long long n = std::stoll(str);
			long long m = PrimalityTests::ModPow(a, k, n);
			std::cout << "ModPow(a, k, n) = " << m << std::endl;
			break;
		}
		case 4:	{
			std::cout << "n = ";
			std::getline(std::cin, str);
			long long n = std::stoll(str);
			std::cout << "t = ";
			std::getline(std::cin, str);
			int t = std::stoi(str);
			bool mr = PrimalityTests::MillerRabin(n, t);
			std::cout << "Miller-Rabin = " << mr << std::endl;
			break;
		}
		case 5:	{
			std::cout << "n = ";
			std::getline(std::cin, str);
			long long n = std::stoll(str);
			std::cout << "t = ";
			std::getline(std::cin, str);
			int t = std::stoi(str);
			bool ss = PrimalityTests::SolovayStrassen(n, t);
			std::cout << "Solavay-Strassen = " << ss << std::endl;
			break;
		}
		}
	}
	return 0;
}

// pch.h: This is a precompiled header file.
// Files listed below are compiled only once, improving build performance for future builds.
// This also affects IntelliSense performance, including code completion and many code browsing features.
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
// Do not add files here that you will be updating frequently as this negates the performance advantage.

#ifndef PCH_H
#define PCH_H
#include <iostream>
#include <random>
#include <string>
#include <vector>
#include "framework.h"
#include "PrimalityTests.h"
#endif //PCH_H

Blog Entry © Sunday, October 12, 2025, by James Pate Williams, Jr. More 64-Bit Factoring Using Pollard’s Cubic Integer Factoring Algorithm