The Ides of March

In which I use Integer arithmetic on Characters to implement a simple Caesar cipher.

Capulet's Orchard
JuliaLang
Author
Published

August 27, 2025

A few days later, I worked on an exercise on Exercism, which aimed to implement the same rotational cipher. For this exercise, I refined the initial code and added this as sections Section 5 and Section 6.

Gaius Iulius Caesar, Museum of antiquities, Public domain, via Wikimedia Commons

Gaius Iulius Caesar, Museum of antiquities, Public domain, via Wikimedia Commons

The Idea

Julia’s Char type was a new concept for me, as discussed in my previous post. To wrap my head around this, I implement a Caesar cipher to encrypt and decrypt simple messages.

As you probably know, this is not a secure encryption method at all. According to Wikipedia: “…the Caesar cipher is easily broken and in modern practice offers essentially no communications security.”

However, I found this a neat little exercise to work with.

Basic concept

In Julia, Int('x') returns the decimal Unicode index for a character. For lower case “x” this would be 120:

Int('x')
120

With this decimal representation of letters available, it is possible to do some mathematical operations on a Char, like addition and subtraction:

Int('x') - 5
115

Now, if we convert the derived new value back to a letter using Char() we have successfully shifted the letter, just like in a Caesar cipher, AKA “shift cipher”:

# shifting 'x' by +2 gives us 'z'
Char(Int('x') + 2)
'z': ASCII/Unicode U+007A (category Ll: Letter, lowercase)

Mathematically, the cyclical shifting around the alphabet can be represented by modular arithmetic. This is described in detail in the Wikipedia article. In short: Encrypting a character \(x\) shifting by \(n\) positions can be described as:

\[ E_n(x)=(x+n)\;mod\;26 \]

Implementing the cipher

The latin alphabet1 only starts at Unicode index 65 (capital letters) and index 97 (lower case letters). To use modular arithmetic, we need to first subtract this number from the character we’re working on in the following functions. After “modulo-shifting”, we add this number back and get the encrypted letter.

function convert_lowercase(character::Char, n_offset)
  if isletter(character)
    Char(((Int(character) - Int('a')) + n_offset ) % 26 + Int('a'))
  else
    return character
  end
end
convert_lowercase (generic function with 1 method)

As you can see above, we only encrypt letters, not punctuation, to keep it simple.

function convert_uppercase(character::Char, n_offset::Int)
  if isletter(character)
      Char(((Int(character) - Int('A')) + n_offset ) % 26 + Int('A'))
  else
    return character
  end
end
convert_uppercase (generic function with 1 method)
function caesar_encrypt(msg::String, n_offset)
  # reduce redundant rotations around the alphabet for offsets > 26
  n_offset = n_offset % 26

  # a negative offset can be mapped to a corresponding positive offset
  if n_offset < 0
    n_offset = 26 + n_offset
  end

  String([if islowercase(x) convert_lowercase(x, n_offset) else convert_uppercase(x, n_offset) end for x in collect(msg)])

end
caesar_encrypt (generic function with 1 method)

Decrypting simply means shifting back each letter by the same offset:

\[ E_n(x)=(x-n)\;mod\;26 \]

Accordingly, the decryption function is the encryption with the negative offset:

caesar_decrypt(msg::String, n_offset) = caesar_encrypt(msg, -n_offset)
caesar_decrypt (generic function with 1 method)

Using the cipher

Now the fun part: Let’s play a bit with the cipher:

NoteAct 1, Scene 2
Soothsayer:
  Beware the ides of March.

The Life and Death of Julius Caesar – William Shakespeare*2

begin
  encrypted_msg = caesar_encrypt("Beware the ides of March.", 5)
  encrypted_msg
end
"Gjbfwj ymj nijx tk Rfwhm."
caesar_decrypt(encrypted_msg, 5)
"Beware the ides of March."

More concise code

To boil down three functions to two, we’ll put the control flow between upper and lower case letters into the rotate function. Using multiple dispatch, we define one version of the cipher function for when we’re working on a Char type and another for when we’re working with a String.

function rotate(n_offset::Int, msg::Char)
    if isletter(msg)
        if isuppercase(msg) 
                Char(((Int(msg) - Int('A')) + n_offset ) % 26 + Int('A'))
        else
                Char(((Int(msg) - Int('a')) + n_offset ) % 26 + Int('a'))
        end
    else
        return msg
    end
end

function rotate(n_offset::Int, msg::String)
    n_offset = n_offset % 26

    if n_offset < 0
        n_offset = 26 + n_offset
    end

    String([rotate(n_offset, x) for x in collect(msg)])

end
rotate (generic function with 2 methods)

Let’s check this version with a longer quote3:

scene2 = """
Thunder and lightning. Enter CAESAR, in his night-gown
CAESAR
Nor heaven nor earth have been at peace to-night:
Thrice hath Calpurnia in her sleep cried out,
'Help, ho! they murder Caesar!' Who's within?
"""

print(rotate(2, scene2))
Vjwpfgt cpf nkijvpkpi. Gpvgt ECGUCT, kp jku pkijv-iqyp
ECGUCT
Pqt jgcxgp pqt gctvj jcxg dggp cv rgceg vq-pkijv:
Vjtkeg jcvj Ecnrwtpkc kp jgt unggr etkgf qwv,
'Jgnr, jq! vjga owtfgt Ecguct!' Yjq'u ykvjkp?

Using Non-Standard String Literals

Julia offers a very interesting way to work with strings, called non-standard string literals.

Based on the abovementioned Julia manual and this comment on stackoverflow, we can implement this as follows:

macro R_str(msg, flag)
    rotate(flag, string(msg))
end
@R_str (macro with 1 method)

With this, we can “encrypt” strings like so:

R"Beware the ides of March."5
"Gjbfwj ymj nijx tk Rfwhm."

This returns the same result, as seen in Section 4. With this macro we can adjust the flag very easily:

begin
  println(R"Beware the ides of March."10)
  println(R"Beware the ides of March."42)

  # test with the initial decryption function
  print(caesar_decrypt(R"Beware the ides of March."23, 23))
end
Logkbo dro snoc yp Wkbmr.
Rumqhu jxu ytui ev Cqhsx.
Beware the ides of March.

Before you move on…

As a final teaser, I’ll leave you an encrypted message without telling you the offset. If you “crack” this Caesar cipher using brute force4, feel free to let me know down below, on Mastodon or on Bluesky!

WarningDecrypt me:

“Bq qr, Yorqb! Qebk cxii, Zxbpxo.”

Footnotes

  1. Julius Caesar was a Roman, speaking Latin…so I’ll stick to the latin letters for the scope of this little blog post.↩︎

  2. The Complete Works of William Shakespeare, https://shakespeare.mit.edu↩︎

  3. Act 2, Scene 2 in Shakespeare’s play, cited above.↩︎

  4. pun intended↩︎

Reuse

Citation

BibTeX citation:
@misc{gebhard2025,
  author = {Gebhard, Christian},
  title = {The {Ides} of {March}},
  date = {2025-08-27},
  url = {https://christiangebhard.com/posts/2025-08-26-julia-CO-06/},
  langid = {en}
}
For attribution, please cite this work as:
Gebhard, Christian. 2025. “The Ides of March.” August 27, 2025. https://christiangebhard.com/posts/2025-08-26-julia-CO-06/.