A cipher is an algorithm that inputs a plaintext string and outputs a ciphertext string, according to some given key.
Example: The shift cipher.
Ciphers, as opposed to codes, operate on strings without regard to their meaning (semantics).
stringToMod26 <- function(x) {utf8ToInt(x)-utf8ToInt("a")}
mod26ToString <- function(x) {intToUtf8(x+utf8ToInt("a"))}
shiftCipher <- function(p,b)
{
pt <- stringToMod26(p)
ct <- (pt + b) %% 26 # add b to each letter
return(mod26ToString(ct))
}
shiftCipher("thisisasecretmessage", 2)
[1] "vjkukucugetgvoguucig"
When we want to consider just the numbers \(0, 1, 2, \ldots, n-1\), and we are doing addition and multiplication modulo \(n\), we say that we are “working in \(\mathbb{Z}_n\),” pronounced “zee mod en”.
More formally, \(\mathbb{Z}_n\) is the set \(\{0, 1, 2, \ldots, n-1\}\) along with multiplication and addition modulo \(n\). Such a set is called a ring.
The shift cipher can be represented by a function \[s: \mathbb{Z}_{26} \longrightarrow \mathbb{Z}_{26}\] given by \[x \stackrel{s}{\longmapsto} x+k\] where \(k \in \mathbb{Z}_{26}\) is the key. To implement the shift cipher, we had to translate strings to \(\mathbb{Z}_{26}\) and back, but the processes of encryption and decryption are performed by the function \(s\) and its inverse \(s^{-1}\), respectively.
In mathematics, an affine function/transformation performs both a shift and a scale. In \(\mathbb{Z}_n\), shifting is done by adding (like the shift cipher), and scaling is done by multiplying. So an affine cipher corresponds to a function \[s: \mathbb{Z}_{26} \longrightarrow \mathbb{Z}_{26}\] given by \[x \stackrel{s}{\longmapsto} \alpha x + \beta\] where the key consist of two elements \(\alpha, \beta \in \mathbb{Z}_{26}\).
Consider the affine cipher given by \(x
\longmapsto 3x + 7\) in \(\mathbb{Z}_{26}\). If cat
is
the plaintext, what is the ciphertext? If dog
is the
ciphertext, what is the plaintext?
a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y | z |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
[1] 2 0 19
[1] 3 14 6
In \(\mathbb{Z}_{n}\), we say that \(b\) is a multiplicative inverse of \(a\) if \(ab = 1\).
What is the multiplicative inverse of \(3\) in \(\mathbb{Z}_{26}\)? Can we use this to calculate \(s^{-1}\) in the above example? Consider:
[1] 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
[26] 25
[1] 0 3 6 9 12 15 18 21 24 1 4 7 10 13 16 19 22 25 2 5 8 11 14 17 20
[26] 23
What is the multiplicative inverse of \(4\) in \(\mathbb{Z}_{26}\)?
[1] 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
[26] 25
[1] 0 4 8 12 16 20 24 2 6 10 14 18 22 0 4 8 12 16 20 24 2 6 10 14 18
[26] 22
We say that \(a\) and \(n\) are “relatively prime” if \(\gcd(a,n)=1\).
Theorem. For any natural numbers \(a\) and \(b\), there exist natural numbers \(c\) and \(d\) such that \(\gcd(a,b)=ca + db\).
This theorem is proved by defining an algorithm to find the GCD. This algorithm is called the Euclidean algorithm, and when it is modified to also give the numbers \(c\) and \(d\), it is called the extended Euclidean algorithm.
\[ \begin{aligned} 1180 &= 2 \cdot 482 + 216 \\ 482 &= 2\cdot 216 + 50 \\ 216 &= 4\cdot 50 +16 \\ 50 &= 3\cdot 16 + 2 \\ 16 &= 8\cdot 2 + 0 \end{aligned} \]
Therefore, \(\gcd(1180,482)=2\), the last nonzero remainder. (why?)
We can find numbers \(c\) and \(d\) such that \(1180c + 482d = 2\) by manipulating these equations. Starting with the second-to-last equation,
\[ {\small \begin{aligned} 2 &= 50-3\cdot 16 \\ &= 50-3(216-4\cdot 50) \\ &= 482-2\cdot 216 -3(216 - 4(482-2\cdot 216)) \\ &= 482-2(1180-2\cdot 482)-3((1180-2\cdot 482)-4(482-2(1180-2\cdot 482))) \\ &= (-2-3-24)1180 + (1+4+6+12+48)482 \\ &= - 29\cdot 1180 + 71 \cdot 482 \end{aligned} } \]
extGCDbigz <- function (a, b, showTrace = FALSE)
{
u <- c(as.bigz(1), as.bigz(0), as.bigz(a))
v <- c(as.bigz(0), as.bigz(1), as.bigz(b))
if(showTrace)
cat(paste("v =", v[1], v[2], v[3], "\n"))
while (v[3] != 0) {
# Invariant: v[1]*a + v[2]*b = v[3]
q <- u[3] %/% v[3]
t <- u - v * q
u <- v
v <- t
if(showTrace)
cat(paste("v =", v[1], v[2], v[3], "\n"))
}
return(list(g = u[3], c = u[1], d = u[2]))
}
extGCDbigz <- function (a, b, showTrace = FALSE)
{
u <- c(as.bigz(1), as.bigz(0), as.bigz(a))
v <- c(as.bigz(0), as.bigz(1), as.bigz(b))
if(showTrace)
cat(paste("v =", v[1], v[2], v[3], "\n"))
while (v[3] != 0) {
# Invariant: v[1]*a + v[2]*b = v[3]
q <- u[3] %/% v[3]
t <- u - v * q
u <- v
v <- t
if(showTrace)
cat(paste("v =", v[1], v[2], v[3], "\n"))
}
return(list(g = u[3], c = u[1], d = u[2]))
}
v = 0 1 24236368482
v = 1 -27741 7229319264
v = -3 83224 2548410690
v = 7 -194189 2132497884
v = -10 277413 415912806
v = 57 -1581254 52933854
v = -409 11346191 45375828
v = 466 -12927445 7558026
v = -3205 88910861 27672
v = 875431 -24285592498 3570
v = -6131222 170088058347 2682
v = 7006653 -194373650845 888
v = -27151181 753209010882 18
v = 1337414522 -37101615184063 6
v = -4039394747 112058054563071 0
$g
Big Integer ('bigz') :
[1] 6
$c
Big Integer ('bigz') :
[1] 1337414522
$d
Big Integer ('bigz') :
[1] -37101615184063
v = 0 1 242363684823423
v = 1 -2 187620957731480
v = -1 3 54742727091943
v = 4 -11 23392776455651
v = -9 25 7957174180641
v = 22 -61 7478428094369
v = -31 86 478746086272
v = 487 -1351 297236800289
v = -518 1437 181509285983
v = 1005 -2788 115727514306
v = -1523 4225 65781771677
v = 2528 -7013 49945742629
v = -4051 11238 15836029048
v = 14681 -40727 2437655485
v = -92137 255600 1210096138
v = 198955 -551927 17463209
v = -13820032 38338563 5134717
v = 41659051 -115567616 2059058
v = -97138134 269473795 1016601
v = 235935319 -654515206 25856
v = -9298615575 25795566829 8217
v = 28131782044 -78041215693 1205
v = -178089307839 494042860987 987
v = 206221089883 -572084076680 218
v = -1002973667371 2782379167707 115
v = 1209194757254 -3354463244387 103
v = -2212168424625 6136842412094 12
v = 18906542154254 -52449202541139 7
v = -21118710578879 58586044953233 5
v = 40025252733133 -111035247494372 2
v = -101169216045145 280656539941977 1
v = 242363684823423 -672348327378326 0
$g
Big Integer ('bigz') :
[1] 1
$c
Big Integer ('bigz') :
[1] -101169216045145
$d
Big Integer ('bigz') :
[1] 280656539941977
The extended Euclidean algorithm runs in linear time on the number of digits (i.e., logarithmic time on the size of the numbers.)
The extended Euclidean algorithm gives us a way to find inverses in \(\mathbb{Z}_n\). Suppose that \(\gcd(a,n)=1\). Then we can use the extended Euclidean algorithm to find integers \(c\) and \(d\) such that \(ca + dn = 1\). This gives us the multiplicative inverse of \(a\). (How?)
Big Integer ('bigz') :
[1] 1
Big Integer ('bigz') object of length 3:
[1] 1 21
[3] -74503643339581175157045500831768513
Big Integer ('bigz') :
[1] 1
gmp
There is also a gmp
function that gives inverses in
\(\mathbb{Z}_n\) directly:
Big Integer ('bigz') :
[1] 21
Suppose \(a\) and \(n\) are not relatively prime. Then there is a common divisor \(d > 1\) such that \(a = kd\) and \(n = ld\).
Each function \(s:\mathbb{Z}_{26}\longrightarrow \mathbb{Z}_{26}\) below defines an affine cipher. For each function, find the decryption function \(s^{-1}\) or prove that no such function exists.
\(x \stackrel{s}{\longmapsto} 11 x + 4\)
\(x \stackrel{s}{\longmapsto} 13 x + 5\)
https://djhunter.github.io/cryptography/programming/01affine.html
https://djhunter.github.io/cryptography/assignments/02shiftaffine.html