How to resolve the algorithm ADFGVX cipher step by step in the Wren programming language
Published on 12 May 2024 09:40 PM
How to resolve the algorithm ADFGVX cipher step by step in the Wren programming language
Table of Contents
Problem Statement
The ADFGVX cipher was a manually applied field cipher used by the German Army during World War I. It was broken in 1918 by the French cryptanalyst Georges Painvin. The workings of the cipher are described in the Wikipedia article, linked to above, and so will not be repeated here. Write routines, functions etc. in your language to:
- Encrypt suitable plaintext and decrypt the resulting cipher text using the ADFGVX cipher algorithm given a Polybius square (see 2. below) and a suitable key. For this purpose suitable means text consisting solely of ASCII upper case letters or digits.
- Create a 6 x 6 Polybius square using a random combination of the letters A to Z and the digits 0 to 9 and then display it.
- Given the number of letters (between 7 and 12 say) to use, create a key by selecting a suitable word at random from unixdict.txt and then display it. The word selected should be such that none of its characters are repeated. Use these routines to create a Polybius square and a 9 letter key. These should then be used to encrypt the plaintext: ATTACKAT1200AM and decrypt the resulting cipher text. Display here the results of both operations. As it's unclear from the Wikipedia article how to handle a final row with fewer elements than the number of characters in the key, either of the methods mentioned in Columnar transposition may be used. In the case of the second method, it is also acceptable to fill any gaps after shuffling by moving elements to the left which makes decipherment harder.
Let's start with the solution:
Step by Step solution about How to resolve the algorithm ADFGVX cipher step by step in the Wren programming language
Source code in the wren programming language
import "random" for Random
import "./ioutil" for FileUtil
import "./seq" for Lst
import "./str" for Char, Str
var rand = Random.new()
var adfgvx = "ADFGVX"
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toList
var createPolybius = Fn.new {
rand.shuffle(alphabet)
var p = Lst.chunks(alphabet, 6)
System.print("6 x 6 Polybius square:\n")
System.print(" | A D F G V X")
System.print("---------------")
for (i in 0...p.count) {
System.write("%(adfgvx[i]) | ")
System.print(p[i].join(" "))
}
return p
}
var createKey = Fn.new { |n|
if (n < 7 || n > 12) Fiber.abort("Key should be within 7 and 12 letters long.")
var candidates = FileUtil.readLines("unixdict.txt").where { |word|
return word.count == n && Lst.distinct(word.toList).count == n &&
word.all { |ch| Char.isAsciiAlphaNum(ch) }
}.toList
var k = Str.upper(candidates[rand.int(candidates.count)])
System.print("\nThe key is %(k)")
return k
}
// helper function to sort the key into alphabetical order
// and return a list of the original indices of its letters.
var orderKey = Fn.new { |key|
var temp = (0...key.count).map { |i| [key[i], i] }.toList
temp.sort { |x, y| x[0].bytes[0] < y[0].bytes[0] }
return temp.map { |e| e[1] }.toList
}
var encrypt = Fn.new { |polybius, key, plainText|
var temp = ""
for (ch in plainText) {
var outer = false
for (r in 0..5) {
for (c in 0..5) {
if (polybius[r][c] == ch) {
temp = temp + adfgvx[r] + adfgvx[c]
outer = true
break
}
}
if (outer) break
}
}
var colLen = (temp.count / key.count).floor
// all columns need to be the same length
if (temp.count % key.count > 0) colLen = colLen + 1
var table = Lst.chunks(temp.toList, key.count)
var lastLen = table[-1].count
if (lastLen < key.count) table[-1] = table[-1] + ([""] * (key.count - lastLen))
var order = orderKey.call(key)
var cols = List.filled(key.count, null)
for (i in 0...cols.count) {
cols[i] = List.filled(colLen, null)
for (j in 0...table.count) cols[i][j] = table[j][order[i]]
}
return cols.map { |col| col.join() }.join(" ")
}
var decrypt = Fn.new { |polybius, key, cipherText|
var colStrs = cipherText.split(" ")
// ensure all columns are same length
var maxColLen = colStrs.reduce(0) { |max, col| max = (col.count > max) ? col.count : max }
var cols = colStrs.map { |s|
return (s.count < maxColLen) ? s.toList + ([""] * (maxColLen - s.count)) : s.toList
}.toList
var table = List.filled(maxColLen, null)
var order = orderKey.call(key)
for (i in 0...maxColLen) {
table[i] = List.filled(key.count, "")
for (j in 0...key.count) table[i][order[j]] = cols[j][i]
}
var temp = table.map { |row| row.join("") }.join("")
var plainText = ""
var i = 0
while (i < temp.count) {
var r = adfgvx.indexOf(temp[i])
var c = adfgvx.indexOf(temp[i+1])
plainText = plainText + polybius[r][c]
i = i + 2
}
return plainText
}
var plainText = "ATTACKAT1200AM"
var polybius = createPolybius.call()
var key = createKey.call(9)
System.print("\nPlaintext : %(plainText)")
var cipherText = encrypt.call(polybius, key, plainText)
System.print("\nEncrypted : %(cipherText)")
var plainText2 = decrypt.call(polybius, key, cipherText)
System.print("\nDecrypted : %(plainText2)")
You may also check:How to resolve the algorithm Arbitrary-precision integers (included) step by step in the ooRexx programming language
You may also check:How to resolve the algorithm Optional parameters step by step in the Bracmat programming language
You may also check:How to resolve the algorithm Happy numbers step by step in the PL/I programming language
You may also check:How to resolve the algorithm Case-sensitivity of identifiers step by step in the Logtalk programming language
You may also check:How to resolve the algorithm Hello world/Standard error step by step in the VBA programming language