YHQL YLGL YLFL - A Caesar cipher​
​by Hakan Kjellerstrand
In the fourth session (“Classical Ciphers”) of “Daily Study Group: Introduction to Cryptography“ (https://www.bigmarker.com/series/daily-study-group-intro-to-cryptography/series_details ), the following Caesar (shift) cipher was given as a quiz/assignment
​
YHQL YLGL YLFL
Julius Caesar
​​
I posted some thoughts about this in the Study Group’s Community thread ( https://community.wolfram.com/groups/-/m/t/2464878 ). Since it might be of some interest for others as well, I’ll create a proper post as well. I also added a simple brute force approach (in “Addendum” below).

First thought

It helped to notice that it was three words of four characters that start with the same character (and a lot of “L”) . It cannot be “alea iacta est” or “aut Caesar aut nihil” for that reason .
Though I did a brute force to confirm it.

First analysis

Here is my (first) more "formal" analysis of this, assuming that the first word should be in Mathematica' s Latin wordlist . This mean that we don’t have to manually seek for the correct solution.
In[]:=
text="yhql ylgl ylfl";​​alpha=Alphabet[];​​latinWords=WordList["KnownWords",Language->"Latin"];​​candidates={StringReplace[text,Thread[Rule[alpha,RotateLeft[alpha,#]]]]}&/@Range[26]​​MemberQ[latinWords,StringSplit[#][[1,1]]]&/@candidates​​Pick[candidates,%]
Out[]=
{{zirm zmhm zmgm},{ajsn anin anhn},{bkto bojo boio},{clup cpkp cpjp},{dmvq dqlq dqkq},{enwr ermr erlr},{foxs fsns fsms},{gpyt gtot gtnt},{hqzu hupu huou},{irav ivqv ivpv},{jsbw jwrw jwqw},{ktcx kxsx kxrx},{ludy lyty lysy},{mvez mzuz mztz},{nwfa nava naua},{oxgb obwb obvb},{pyhc pcxc pcwc},{qzid qdyd qdxd},{raje reze reye},{sbkf sfaf sfzf},{tclg tgbg tgag},{udmh uhch uhbh},{veni vidi vici},{wfoj wjej wjdj},{xgpk xkfk xkek},{yhql ylgl ylfl}}
Out[]=
{False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,True,False,False,False}
Out[]=
{{veni vidi vici}}

Second analysis

Here is another take on this, though it might be overkill for this problem. But let' s say that - for some reason - we don' t want to test all the possible Caesar shifts, for example if they are too costly
​
Then we can use the observation that the letter "l" is more frequent than the other.
In[]:=
text="yhql ylgl ylfl";​​CharacterCounts[text]
Out[]=
l5,y3, 2,f1,g1,q1,h1
What will be the first substitute to test, i . e . what is the commonest character in Latin?
Unfortunately, there is no letter frequency for Latin in WL.
In[]:=
LanguageData["Latin","LetterFrequency"]
Out[]=
Missing[NotAvailable]
So we have to roll our own, which shows that the character “i” is the most common character in Latin.
In[]:=
latinWords=WordList["KnownWords",Language->"Latin"];​​CharacterCounts[StringJoin[latinWords]]
Out[]=
i6307,e6008,s5359,a5324,u5276,o5189,r5013,t4035,n3395,c3240,l2763,m2490,p2220,d1609,b1004,g946,f896,v869,h469,x409,q363,y97,æ94,j51,C38,A34,H19,M16,z13,I12,T11,P11,B10,S9,R8,L8,V6,G6,*5,O4,F4,N3,E3,D3,k3,Æ3,Z2,-2,U1,-1,Q1
Let' s now use this knowledge to first test the shift that replaces an "i" with "l" :
In[]:=
alpha=Alphabet[];​​shift=LetterNumber["i"]-LetterNumber["l"]​​keytable=Thread[Rule[alpha,RotateLeft[alpha,shift]]]​​StringReplace["yhql ylgl ylfl",keytable]
Out[]=
-3
Out[]=
{ax,by,cz,da,eb,fc,gd,he,if,jg,kh,li,mj,nk,ol,pm,qn,ro,sp,tq,ur,vs,wt,xu,yv,zw}
Out[]=
veni vidi vici
Which happens to be the correct shift and solves the problem.
​
Note : The shift found is - 3 which is the same as shift 23 (26 + -3 = 23) .

Addendum

Just to be a little more complete about this, here’s a brute force variant.
In[]:=
text="yhql ylgl ylfl";​​alpha=Alphabet[];​​Table[{shift,StringReplace[text,Thread[Rule[alpha,RotateLeft[alpha,shift]]]]},{shift,0,25}]//TableForm
Out[]//TableForm=
0
yhql ylgl ylfl
1
zirm zmhm zmgm
2
ajsn anin anhn
3
bkto bojo boio
4
clup cpkp cpjp
5
dmvq dqlq dqkq
6
enwr ermr erlr
7
foxs fsns fsms
8
gpyt gtot gtnt
9
hqzu hupu huou
10
irav ivqv ivpv
11
jsbw jwrw jwqw
12
ktcx kxsx kxrx
13
ludy lyty lysy
14
mvez mzuz mztz
15
nwfa nava naua
16
oxgb obwb obvb
17
pyhc pcxc pcwc
18
qzid qdyd qdxd
19
raje reze reye
20
sbkf sfaf sfzf
21
tclg tgbg tgag
22
udmh uhch uhbh
23
veni vidi vici
24
wfoj wjej wjdj
25
xgpk xkfk xkek