Artifacts on this Page
All fonts, SVGs, code, and other artifacts on this page copyright © 2021 ruben vuittonet, jr. Free for all non-commercial purposes. Otherwise, contact me at ruben.vuittonet@gmail.com for more information. All of the font, code, and test-project artifacts on this page can be found here by following the link, below.

About the Zodiac Killer
Basic Info
The Zodiac Killer, or simply Zodiac or The Zodiac, is the pseudonym of a serial killer who operated in Northern California in the late 1960s.The case has been described as the most famous unsolved murder case in American history and has become a fixture of popular culture, inspiring a mateur detectives to attempt to resolve it and entertainment such as films, television, novels, and video games.
On a few occasions, the Zodiac Killer communicated with the public. In one such instance, the communication took the form of coded document 340 characters in length.
It would take 51 years for this cipher to be broken. Even then, it yielded no information in regard to the identify of the Zodiac Killer.
December 11th 2020 will go down as a momentous day in the Zodiac Killer story, as the one on which Dave Oranchak (USA), Sam Blake (Australia) and Jarl Van Eycke (Belgium) finally cracked and publicly released the solution to the 340 cipher after 51 years and one month.

The Zodiac Cipher is a multi-letter substitution cipher, which is to say that there is not a one-to-one correspondence between the plaintext letters and the ciper glyphs. Some plaintext letters are represented by more than one cipher glyph.

The character map illustrates the letter substitutions for all of the letters found in the Zodiac 340 Cipher, a message from the Zodiac Killer containing 340 characters. It was mailed to the San Francisco Chronicle in 1969, although it was not broken until 2020 (51 years).

As is evident from the image, the Zodaic employed a rather unique set of glyphs for the encryption, including the crosshair glyph that was employed as a sort of signature on Zodiac communications.

So, I decided to create a font and a piece of software for manipulating the Zodiac Cipher. For those letters with more than one glyph I randomly generated which glyph would be used for each character encipherment. I then analyzed the differences between one encipherment of text and the next for a total of 4 encipherments.

The percentage difference between adjacent encipherments: 49%, 47%, 46%, 48%.

The limited number of communications from the Zodiac coupled to the almost 50% variability in the encipherment for the same letters made the Zodiac Cipher extremely difficult to break.
Having Fun - C# WinForms
The SVGs
I decided I wanted to have some fun with the cipher, so I downloaded a copy of the 340 cipher, identified all of the glyphs, mapped the glyphs to their plaintext letters, and started designing. The result is a set of 64 glyphs (which were used to create the nearby image)…
The Font
The Zodiac Cipher TTF can be found here .

This font is the copyrighted property of Ruben Vuittonet, Jr. All rights reserved. It is free for non-commercial use. For all other uses, contact me at ruben.vuittonet@gmail.com.

Of course, while the SVGs are useful, they are not nearly as useful as a font, so, the next day, I created a font. This is a common practice of mine for almost any of my projects that contain special symbols or glyphs. This one presented some interesting challenges, because some of the plaintext characters have more than one glyph representation. The font, therefore, requires a process for converting plain text to the Zodiac Cipher.

The code, below, provides the model for storing a list of letters in the cipher and the number of glyphs in the cipher for each letter.
Font Usage
The use of the font requires a two-step process.
  1. Each letter of the plaintext must be converted to a ‘Zodiac’ letter. For example, there are 5 glyphs for the plaintext latter, ‘A’. So, the plaintext latter ‘A’ must be converted to one of A1, A2, A3, A4, or A5.
  2. The ‘Zodiac’ letter must be converted to a letter in the font. For example, if the ‘Zodiac’ letter is A1, it is mapped to ‘u’.
  3. The code example, below, converts “ABCDEFGHIMNOPRSTUVWY” to the Zodiac Cipher. Note: because some plaintext letters in the Zodiac Cipher have multiple glyph representations, the result of your execution of the code, below, may be different than the result shown.

    using System;
    using System.Linq;
    using System.Collections.Generic;

    namespace GlyphicLib.Model
    {
       /// <summary>   
       /// Provides a model for holding a plaintext letter and the   
       /// number of cipher glyphs that exist for that letter.   
       /// </summary>   
       [Serializable]
       public class ZodiacLetter
       {
          private String letter = " ";
          private int    count = 1;

          /// <summary>      
          /// Plain Constructor      
          /// </summary>      
          public ZodiacLetter()
          {
          }
          /// <summary>      
          /// Initializing Constructor      
          /// </summary>      
          public ZodiacLetter(String aLetterint aCount)
          {
             letter = aLetter ?? "";
             count = Math.Max(aCount1);
          }
          /// <summary>      
          /// Accessor Mutator for the count member of type int      
          /// </summary>      
          public int Count
          {
             get { return count; }
             set { count = value; }
          }
          /// <summary>      
          /// Accessor Mutator for the letter member of type String      
          /// </summary>      
          public String Letter
          {
             get { return letter; }
             set
             {
                if (value == null)
                   value = " ";
                else if (value.Length == 0)
                   value = " ";
                else if (value.Length > 1)
                   value = value.Substring(01);

                letter = value;
             }
          }
       }   
    }

    using System;
    using System.Windows.Forms;

    namespace GlyphicLib.Model {    
       /// <summary>   
       /// Provides a class for producing the font letters for the   
       /// Zodiac Cipher   
       /// </summary>   
       public static class ZodiacAlphabetTester   {      
          /// <summary>      
          /// Convers the text "ABCDEFGHIMNOPRSTUVWY" to the cipher glyphs mapped      
          /// to the ZodiacCipher.ttf      
          /// </summary>      
          /// <param name="sender"></param>      
          /// <param name="e"></param>      
          public static String Test(string text = "")
          {         
             ZodiacLetters letters    =  new ZodiacLetters();         
             ZodiacFontMap fontMap    =  new ZodiacFontMap();         
             String        zLetter;         
             String        fontLetter;         
             String        fontText   =  "";         

             if(string.IsNullOrEmpty(text?.Trim())) 
                text = "ABCDEFGHIMNOPRSTUVWY";

             foreach (char chr in text)         
             {            
                // Converts the plain text to a 'Zodiac' Letter             
                // (e.g. A -> A1, A2, A3, A4, or A5)
                
                zLetter = letters.Letter(chr);            
                
                // Converts the 'Zodiac Letter' to the font letter.            
                fontLetter = fontMap.ZodiacToFont(zLetter);            
                fontText += fontLetter;         
             }         
             return fontText;      
          }   
       }
    }
    using System;
    using System.Windows.Forms;

    namespace GlyphicLib.Model {    
       /// <summary>   
       /// Provides a class for producing the font letters for the   
       /// Zodiac Cipher   
       /// </summary>   
       public static class ZodiacAlphabetTester   {      
          /// <summary>      
          /// Convers the text "ABCDEFGHIMNOPRSTUVWY" to the cipher glyphs mapped      
          /// to the ZodiacCipher.ttf      
          /// </summary>      
          /// <param name="sender"></param>      
          /// <param name="e"></param>      
          public static String Test(string text = "")
          {         
             ZodiacLetters letters    =  new ZodiacLetters();         
             ZodiacFontMap fontMap    =  new ZodiacFontMap();         
             String        zLetter;         
             String        fontLetter;         
             String        fontText   =  "";         

             if(string.IsNullOrEmpty(text?.Trim())) 
                text = "ABCDEFGHIMNOPRSTUVWY";

             foreach (char chr in text)         
             {            
                // Converts the plain text to a 'Zodiac' Letter             
                // (e.g. A -> A1, A2, A3, A4, or A5)
                
                zLetter = letters.Letter(chr);            
                
                // Converts the 'Zodiac Letter' to the font letter.            
                fontLetter = fontMap.ZodiacToFont(zLetter);            
                fontText += fontLetter;         
             }         
             return fontText;      
          }   
       }
    }
    namespace GlyphicLib.Model
    {
       /// <summary>   
       /// Provides the model for mapping a font character to a Zodiac Letter    
       /// (0 > D2, 1 > E2, 2 > E4, 3 > Y2, etc)   
       /// </summary>   
       public class ZodiacFontChar
       {
          private String fontChar = "";
          private String letter   = "";

          /// <summary>      
          /// Constructor for a ZodiacFontChar      
          /// </summary>      
          public ZodiacFontChar(String aFontCharString aLetter)
          {
             fontChar = aFontChar ?? "";
             letter   = aLetter ?? "";
          }
          /// <summary>      
          /// Accessor Mutator for the fontChar member of type String      
          /// </summary>      
          public String FontChar
          {
             get { return fontChar; }
             set { fontChar = value ?? ""; }
          }
          /// <summary>      
          /// Accessor Mutator for the letter member of type String      
          /// </summary>      
          public String Letter
          {
             get { return letter; }
             set { letter = value ?? ""; }
          }
       }

       /// <summary>   
       /// Provides the model for the complete mapping of Zodiac    
       /// Letters to font letters.   
       /// </summary>   
       public class ZodiacFontMap : List<ZodiacFontChar>
       {
          /// <summary>      
          /// Initialized the Zodiac Letter to font letter map.      
          /// </summary>      
          public ZodiacFontMap()
          {
             Add(new ZodiacFontChar("0""D2"));
             Add(new ZodiacFontChar("1""E2"));
             Add(new ZodiacFontChar("2""E4"));
             Add(new ZodiacFontChar("3""Y2"));
             Add(new ZodiacFontChar("4""E5"));
             Add(new ZodiacFontChar("5""N4"));
             Add(new ZodiacFontChar("6""L2"));
             Add(new ZodiacFontChar("7""R2"));
             Add(new ZodiacFontChar("8""F1"));
             Add(new ZodiacFontChar("9""B2"));
             Add(new ZodiacFontChar("A""T6"));
             Add(new ZodiacFontChar("B""I2"));
             Add(new ZodiacFontChar("C""E6"));
             Add(new ZodiacFontChar("D""S3"));
             Add(new ZodiacFontChar("E""P2"));
             Add(new ZodiacFontChar("F""A2"));
             Add(new ZodiacFontChar("G""I4"));
             Add(new ZodiacFontChar("H""G1"));
             Add(new ZodiacFontChar("I""A4"));
             Add(new ZodiacFontChar("J""O1"));
             Add(new ZodiacFontChar("K""E3"));
             Add(new ZodiacFontChar("L""A3"));
             Add(new ZodiacFontChar("M""I3"));
             Add(new ZodiacFontChar("N""S1"));
             Add(new ZodiacFontChar("O""U3"));
             Add(new ZodiacFontChar("P""O2"));
             Add(new ZodiacFontChar("Q""D3"));
             Add(new ZodiacFontChar("R""R3"));
             Add(new ZodiacFontChar("S""L3"));
             Add(new ZodiacFontChar("T""S4"));
             Add(new ZodiacFontChar("U""O3"));
             Add(new ZodiacFontChar("V""W2"));
             Add(new ZodiacFontChar("W""R4"));
             Add(new ZodiacFontChar("X""N5"));
             Add(new ZodiacFontChar("Y""I5"));
             Add(new ZodiacFontChar("a""R5"));
             Add(new ZodiacFontChar("b""N3"));
             Add(new ZodiacFontChar("c""O4"));
             Add(new ZodiacFontChar("d""I1"));
             Add(new ZodiacFontChar("e""R1"));
             Add(new ZodiacFontChar("f""Y1"));
             Add(new ZodiacFontChar("g""E1"));
             Add(new ZodiacFontChar("h""M1"));
             Add(new ZodiacFontChar("i""V1"));
             Add(new ZodiacFontChar("j""H1"));
             Add(new ZodiacFontChar("k""S2"));
             Add(new ZodiacFontChar("l""T3"));
             Add(new ZodiacFontChar("m""A5"));
             Add(new ZodiacFontChar("n""W1"));
             Add(new ZodiacFontChar("q""D1"));
             Add(new ZodiacFontChar("r""T1"));
             Add(new ZodiacFontChar("s""B1"));
             Add(new ZodiacFontChar("t""U2"));
             Add(new ZodiacFontChar("u""A1"));
             Add(new ZodiacFontChar("v""T2"));
             Add(new ZodiacFontChar("w""N1"));
             Add(new ZodiacFontChar("x""N2"));
             Add(new ZodiacFontChar("y""U1"));
             Add(new ZodiacFontChar("z""P1"));
             Add(new ZodiacFontChar("'""L1"));
             Add(new ZodiacFontChar("~""C1"));
             Add(new ZodiacFontChar("!""T4"));
             Add(new ZodiacFontChar("@""T5"));
          }      
          /// <summary>      
          /// Converts a Zodiac Letter (A1, A2, D1, et al) to a font letter.       
          /// </summary>      
          /// <param name="zodiac"></param>      
          /// <returns></returns>      
          public String ZodiacToFont(String zodiac) {         
             ZodiacFontChar chr =            
                (               
                   from   item                
                   in     this               
                   where  item.Letter == zodiac               
                   select item            
                ).FirstOrDefault();         
             
             if (chr != null)            
                return chr.FontChar;         
             
             return "";      
          }      
          
          /// <summary>      
          /// Converts a list of Zodiac Letters (A1, A2, D1, et al) to their       
          /// font letters. The resulting text is formatted in columns specified      
          /// by the width parameter.      
          /// </summary>      
          /// <param name="zodiacChars"></param>      
          /// <returns></returns>      
          public string Convert(List<stringzodiacCharsint width)      
          {         
             if(zodiacChars == null)             
                return "[The Zodiac Chars are null]";                      
             
             width = Math.Max(1width);

             String result = "";          
             int    cnt    = 0;         
             
             foreach(String chr in zodiacChars)         
             {            
                result += ZodiacToFont(chr);            
                
                if (++cnt == width)            
                {               
                   result += "\n";               
                   cnt     = 0;            
                }         
             }         

             return result;      
          }   
       }
    }
The Test App
The artifact bundle for this page includes a license file, the ZodiacCipher.ttf, the four code artifacts (.cs) used this page, and a test application. The artifacts in the bundle are the copyrighted property of Ruben Vuittonet, Jr. Non-commercial use is free. For other uses, contact me at ruben.vuittonet@gmail.com. The code provided for download can be used to create an application like the one shown below.



This application tests the encipherment of “ABCDEFGHIMNOPRSTUVWY”. Running the test multiple times will result in different ciphertexts.
Uses
T-Shirts
The first idea I had for using the SVGs and/or font was for a T-shirt. For Frank’s eulogy, I incorporated various stories from our childhood interspersed with lyrics from music both he and I enjoyed. One such song was Daniel, by Elton John. For some reason, it has always reminded me of Frank.

So, I took 225 (152) letters from the lyrics of Elton John’s Daniel and enciphered them. I loaded the cipher into Corel Draw and colored most of the glyphs medium blue (meant for a dark-blue T-shift). I changed a smattering of glyphs red and the center-most one yellow.

The result is the conversion of a cipher employed by a murderer into something positive.

Sadly, a computer crash had me lose the photo of the shirt.
The plaintext for the cipher (spaces added for clarity):

DANIEL IS TRAVELING TONIGHT ON A PLANE I CAN SEE THE RED TAIL LIGHTS HEADING FOR SPAIN AND I CAN SEE DANIEL WAVING GOODBYE OH IT LOOKS LIKE DANIEL MUST BE THE CLOUDS IN MY EYES THEY SAY SPAIN IS PRETTY THOUGH IVE NEVER BEEN AND DANIEL SAYS ITS THE BEST PLACE THAT HES EVER SEEN MISS U
An Interactive Editor
Plaintext (supported letters: ABCDEFGHIMNOPRSTUVWY)
 
//------------------------------------------------------------------------------
class Zodiac {
   
   zodiacLetters = null;
   fontMap       = null;
   useImages     = false;
   imagePath     = "";
   
   constructor(aImagePathaUseImages) {
      
      if(aImagePath)
        this.imagePath = aImagePath
        
      if(aUseImages)
         this.useImages = aUseImages;
      
      this.zodiacLetters = 
      {
         "A"5,
         "B"2,
         "C"1,
         "D"3,
         "E"6,
         "F"1,
         "G"1,
         "H"1,
         "I"5,
         "L"3,
         "M"1,
         "N"5,
         "O"4,
         "P"2,
         "R"5,
         "S"4,
         "T"6,
         "U"3,
         "V"1,
         "W"2,
         "Y"2
      };
      this.fontMap = 
      {
        "D2" : "0",
        "E2" : "1",
        "E4" : "2",
        "Y2" : "3",
        "E5" : "4",
        "N4" : "5",
        "L2" : "6",
        "R2" : "7",
        "F1" : "8",
        "B2" : "9",
        "T6" : "A",
        "I2" : "B",
        "E6" : "C",
        "S3" : "D",
        "P2" : "E",
        "A2" : "F",
        "I4" : "G",
        "G1" : "H",
        "A4" : "I",
        "O1" : "J",
        "E3" : "K",
        "A3" : "L",
        "I3" : "M",
        "S1" : "N",
        "U3" : "O",
        "O2" : "P",
        "D3" : "Q",
        "R3" : "R",
        "L3" : "S",
        "S4" : "T",
        "O3" : "U",
        "W2" : "V",
        "R4" : "W",
        "N5" : "X",
        "I5" : "Y",
        "R5" : "a",
        "N3" : "b",
        "O4" : "c",
        "I1" : "d",
        "R1" : "e",
        "Y1" : "f",
        "E1" : "g",
        "M1" : "h",
        "V1" : "i",
        "H1" : "j",
        "S2" : "k",
        "T3" : "l",
        "A5" : "m",
        "W1" : "n",
        "D1" : "q",
        "T1" : "r",
        "B1" : "s",
        "U2" : "t",
        "A1" : "u",
        "T2" : "v",
        "N1" : "w",
        "N2" : "x",
        "U1" : "y",
        "P1" : "z",
        "L1" : "'",
        "C1" : "~",
        "T4" : "!",
        "T5" : "@"
      }
   }
  
   Count(letter){
      result = zodiacLetters[letter];
      
      if(result)
         return result
      
      return 0;
   }
   
   processZodiacCipher(elecontainer)
   {
      var eleContainer = $("#" + container);
      var text         = ele.value
      var chr          = "";
      var count        = 0;
      var idx          = -1;
      var zodiacLetter = "";
      var cipher       = "";
      
      if(eleContainer.length == 1)
      {
         for (var i = 0i < text.lengthi++
         {
            chr   = text.charAt(i).toUpperCase();
            count = this.zodiacLetters[chr];
            
            if(count > 0)
            {
               idx          =  Math.floor(Math.random() /span> count+ 1;
               zodiacLetter =  chr + idx;
               
               if(!this.useImages)
                  cipher += this.fontMap[zodiacLetter];
               else
                  cipher += "<img src='" + this.imagePath + zodiacLetter + ".svg'/>"
                  
            } 
         }
         
         $(eleContainer).html(cipher + "&nbsp;");
      }
   }
}
Keyed Words
Corel Draw