Classical Cryptosystems#
A convenient user interface to various classical ciphers. These include:
affine cipher; see
AffineCryptosystem
Hill or matrix cipher; see
HillCryptosystem
shift cipher; see
ShiftCryptosystem
substitution cipher; see
SubstitutionCryptosystem
transposition cipher; see
TranspositionCryptosystem
Vigenere cipher; see
VigenereCryptosystem
These classical cryptosystems support alphabets such as:
the capital letters of the English alphabet; see
AlphabeticStrings()
the hexadecimal number system; see
HexadecimalStrings()
the binary number system; see
BinaryStrings()
the octal number system; see
OctalStrings()
the radix-64 number system; see
Radix64Strings()
AUTHORS:
David Kohel (2007): initial version with the Hill, substitution, transposition, and Vigenere cryptosystems.
Minh Van Nguyen (2009-08): shift cipher, affine cipher
- class sage.crypto.classical.AffineCryptosystem(A)#
Bases:
SymmetricKeyCryptosystem
Create an affine cryptosystem.
Let \(A = \{ a_0, a_1, a_2, \dots, a_{n-1} \}\) be a non-empty alphabet consisting of \(n\) unique elements. Define a mapping \(f : A \longrightarrow \ZZ / n\ZZ\) from the alphabet \(A\) to the set \(\ZZ / n\ZZ\) of integers modulo \(n\), given by \(f(a_i) = i\). Thus we can identify each element of the alphabet \(A\) with a unique integer \(0 \leq i < n\). A key of the affine cipher is an ordered pair of integers \((a, b) \in \ZZ / n\ZZ \times \ZZ / n\ZZ\) such that \(\gcd(a, n) = 1\). Therefore the key space is \(\ZZ / n\ZZ \times \ZZ / n\ZZ\). Since we assume that \(A\) does not have repeated elements, the mapping \(f : A \longrightarrow \ZZ/ n\ZZ\) is bijective. Encryption and decryption functions are both affine functions. Let \((a,b)\) be a secret key, i.e. an element of the key space, and let \(p\) be a plaintext character and consequently \(p \in \ZZ / n\ZZ\). Then the ciphertext character \(c\) corresponding to \(p\) is given by
\[c \equiv ap + b \pmod{n}\]Similarly, given a ciphertext character \(c \in \ZZ / n\ZZ\) and a secret key \((a,b)\), we can recover the corresponding plaintext character as follows:
\[p \equiv a^{-1} (c - b) \pmod{n}\]where \(a^{-1}\) is the inverse of \(a\) modulo \(n\). Use the bijection \(f : A \longrightarrow \ZZ / n\ZZ\) to convert \(c\) and \(p\) back to elements of the alphabet \(A\). Currently, only the following alphabet is supported for the affine cipher:
capital letters of the English alphabet as implemented in
AlphabeticStrings()
EXAMPLES:
Encryption and decryption over the capital letters of the English alphabet:
sage: A = AffineCryptosystem(AlphabeticStrings()); A Affine cryptosystem on Free alphabetic string monoid on A-Z sage: P = A.encoding("The affine cryptosystem generalizes the shift cipher.") sage: P THEAFFINECRYPTOSYSTEMGENERALIZESTHESHIFTCIPHER sage: a, b = (9, 13) sage: C = A.enciphering(a, b, P); C CYXNGGHAXFKVSCJTVTCXRPXAXKNIHEXTCYXTYHGCFHSYXK sage: A.deciphering(a, b, C) THEAFFINECRYPTOSYSTEMGENERALIZESTHESHIFTCIPHER sage: A.deciphering(a, b, C) == P True
We can also use functional notation to work through the previous example:
sage: A = AffineCryptosystem(AlphabeticStrings()); A Affine cryptosystem on Free alphabetic string monoid on A-Z sage: P = A.encoding("The affine cryptosystem generalizes the shift cipher.") sage: P THEAFFINECRYPTOSYSTEMGENERALIZESTHESHIFTCIPHER sage: a, b = (9, 13) sage: E = A(a, b); E Affine cipher on Free alphabetic string monoid on A-Z sage: C = E(P); C CYXNGGHAXFKVSCJTVTCXRPXAXKNIHEXTCYXTYHGCFHSYXK sage: aInv, bInv = A.inverse_key(a, b) sage: D = A(aInv, bInv); D Affine cipher on Free alphabetic string monoid on A-Z sage: D(C) THEAFFINECRYPTOSYSTEMGENERALIZESTHESHIFTCIPHER sage: D(C) == P True sage: D(C) == P == D(E(P)) True
Encrypting the ciphertext with the inverse key also produces the plaintext:
sage: A = AffineCryptosystem(AlphabeticStrings()) sage: P = A.encoding("Encrypt with inverse key.") sage: a, b = (11, 8) sage: C = A.enciphering(a, b, P) sage: P; C ENCRYPTWITHINVERSEKEY AVENMRJQSJHSVFANYAOAM sage: aInv, bInv = A.inverse_key(a, b) sage: A.enciphering(aInv, bInv, C) ENCRYPTWITHINVERSEKEY sage: A.enciphering(aInv, bInv, C) == P True
For a secret key \((a,b) \in \ZZ/n\ZZ \times \ZZ/n\ZZ\), if \(a = 1\) then any affine cryptosystem with key \((1, b)\) for any \(b \in \ZZ/n\ZZ\) is a shift cryptosystem. Here is how we can create a Caesar cipher using an affine cipher:
sage: caesar = AffineCryptosystem(AlphabeticStrings()) sage: a, b = (1, 3) sage: P = caesar.encoding("abcdef"); P ABCDEF sage: C = caesar.enciphering(a, b, P); C DEFGHI sage: caesar.deciphering(a, b, C) == P True
Any affine cipher with keys of the form \((a,0) \in \ZZ/n\ZZ \times \ZZ/n\ZZ\) is called a decimation cipher on the Roman alphabet, or decimation cipher for short:
sage: A = AffineCryptosystem(AlphabeticStrings()) sage: P = A.encoding("A decimation cipher is a specialized affine cipher.") sage: a, b = (17, 0) sage: C = A.enciphering(a, b, P) sage: P; C ADECIMATIONCIPHERISASPECIALIZEDAFFINECIPHER AZQIGWALGENIGVPQDGUAUVQIGAFGJQZAHHGNQIGVPQD sage: A.deciphering(a, b, C) == P True
Generate a random key for encryption and decryption:
sage: A = AffineCryptosystem(AlphabeticStrings()) sage: P = A.encoding("An affine cipher with a random key.") sage: a, b = A.random_key() sage: C = A.enciphering(a, b, P) sage: A.deciphering(a, b, C) == P True
REFERENCES:
- brute_force(C, ranking='none')#
Attempt a brute force cryptanalysis of the ciphertext
C
.INPUT:
C
– A ciphertext over one of the supported alphabets of this affine cryptosystem. See the classAffineCryptosystem
for documentation on the supported alphabets.ranking
– (default"none"
) the method to use for ranking all possible keys. Ifranking="none"
, then do not use any ranking function. The following ranking functions are supported:"chi_square"
– the chi-square ranking function as implemented in the methodrank_by_chi_square()
."squared_differences"
– the squared differences ranking function as implemented in the methodrank_by_squared_differences()
.
OUTPUT:
All the possible plaintext sequences corresponding to the ciphertext
C
. This method effectively uses all the possible keys in this affine cryptosystem to decryptC
. The method is also referred to as exhaustive key search. The output is a dictionary of key, candidate decipherment pairs.
EXAMPLES:
Cryptanalyze using all possible keys with the option
ranking="none"
:sage: A = AffineCryptosystem(AlphabeticStrings()) sage: a, b = (3, 7) sage: P = A.encoding("Linear"); P LINEAR sage: C = A.enciphering(a, b, P) sage: L = A.brute_force(C) sage: sorted(L.items())[:26] # display 26 candidate decipherments [((1, 0), OFUTHG), ((1, 1), NETSGF), ((1, 2), MDSRFE), ((1, 3), LCRQED), ((1, 4), KBQPDC), ((1, 5), JAPOCB), ((1, 6), IZONBA), ((1, 7), HYNMAZ), ((1, 8), GXMLZY), ((1, 9), FWLKYX), ((1, 10), EVKJXW), ((1, 11), DUJIWV), ((1, 12), CTIHVU), ((1, 13), BSHGUT), ((1, 14), ARGFTS), ((1, 15), ZQFESR), ((1, 16), YPEDRQ), ((1, 17), XODCQP), ((1, 18), WNCBPO), ((1, 19), VMBAON), ((1, 20), ULAZNM), ((1, 21), TKZYML), ((1, 22), SJYXLK), ((1, 23), RIXWKJ), ((1, 24), QHWVJI), ((1, 25), PGVUIH)]
Use the chi-square ranking function, i.e.
ranking="chisquare"
:sage: A = AffineCryptosystem(AlphabeticStrings()) sage: a, b = (3, 7) sage: P = A.encoding("Linear functions for encrypting and decrypting."); P LINEARFUNCTIONSFORENCRYPTINGANDDECRYPTING sage: C = A.enciphering(a, b, P) sage: Rank = A.brute_force(C, ranking="chisquare") sage: Rank[:10] # display only the top 10 candidate keys [((3, 7), LINEARFUNCTIONSFORENCRYPTINGANDDECRYPTING), ((23, 25), VYTCGPBMTENYSTOBSPCTEPIRNYTAGTDDCEPIRNYTA), ((1, 12), CTIHVUKDIBATLIXKLUHIBUPOATINVIEEHBUPOATIN), ((11, 15), HSRYELDAROVSWRQDWLYROLUBVSRIERTTYOLUBVSRI), ((25, 1), NWHIUVFMHOPWEHSFEVIHOVABPWHCUHLLIOVABPWHC), ((25, 7), TCNOABLSNUVCKNYLKBONUBGHVCNIANRROUBGHVCNI), ((15, 4), SHIBVOWZILEHDIJWDOBILOFYEHIRVIGGBLOFYEHIR), ((15, 23), PEFYSLTWFIBEAFGTALYFILCVBEFOSFDDYILCVBEFO), ((7, 10), IDUFHSYXUTEDNULYNSFUTSVGEDURHUMMFTSVGEDUR), ((19, 22), QVETRGABEFUVLENALGTEFGDSUVEHREMMTFGDSUVEH)]
Use the squared differences ranking function, i.e.
ranking="squared_differences"
:sage: Rank = A.brute_force(C, ranking="squared_differences") sage: Rank[:10] # display only the top 10 candidate keys [((3, 7), LINEARFUNCTIONSFORENCRYPTINGANDDECRYPTING), ((23, 6), GJENRAMXEPYJDEZMDANEPATCYJELREOONPATCYJEL), ((23, 25), VYTCGPBMTENYSTOBSPCTEPIRNYTAGTDDCEPIRNYTA), ((19, 22), QVETRGABEFUVLENALGTEFGDSUVEHREMMTFGDSUVEH), ((19, 9), DIRGETNORSHIYRANYTGRSTQFHIRUERZZGSTQFHIRU), ((23, 18), KNIRVEQBITCNHIDQHERITEXGCNIPVISSRTEXGCNIP), ((17, 16), GHORBEIDOJMHFOVIFEROJETWMHOZBOAARJETWMHOZ), ((21, 14), AHEZRMOFEVQHTEBOTMZEVMNIQHEDREKKZVMNIQHED), ((1, 12), CTIHVUKDIBATLIXKLUHIBUPOATINVIEEHBUPOATIN), ((7, 18), SNEPRCIHEDONXEVIXCPEDCFQONEBREWWPDCFQONEB)]
- deciphering(a, b, C)#
Decrypt the ciphertext
C
with the key(a, b)
using affine cipher decryption.INPUT:
a, b
– a secret key belonging to the key space of this affine cipher. This key must be an element of \(\ZZ/n\ZZ \times \ZZ/n\ZZ\) such that \(\gcd(a,n) = 1\) with \(n\) being the size of the ciphertext and plaintext spaces.C
– a string of ciphertext; possibly an empty string. Characters in this string must be encoded using one of the supported alphabets. See the methodencoding()
for more information.
OUTPUT:
The plaintext corresponding to the ciphertext
C
.
EXAMPLES:
Decryption over the capital letters of the English alphabet:
sage: A = AffineCryptosystem(AlphabeticStrings()) sage: a, b = (5, 2) sage: P = A.encoding("Affine functions are linear functions.") sage: C = A.enciphering(a, b, P); C CBBQPWBYPMTQUPOCJWFQPWCJBYPMTQUPO sage: P == A.deciphering(a, b, C) True
The previous example can also be worked through using functional notation:
sage: A = AffineCryptosystem(AlphabeticStrings()) sage: a, b = (5, 2) sage: P = A.encoding("Affine functions are linear functions.") sage: E = A(a, b); E Affine cipher on Free alphabetic string monoid on A-Z sage: C = E(P); C CBBQPWBYPMTQUPOCJWFQPWCJBYPMTQUPO sage: aInv, bInv = A.inverse_key(a, b) sage: D = A(aInv, bInv); D Affine cipher on Free alphabetic string monoid on A-Z sage: D(C) == P True
If the ciphertext is an empty string, then the plaintext is also an empty string regardless of the value of the secret key:
sage: a, b = A.random_key() sage: A.deciphering(a, b, A.encoding("")) sage: A.deciphering(a, b, A.encoding(" "))
- enciphering(a, b, P)#
Encrypt the plaintext
P
with the key(a, b)
using affine cipher encryption.INPUT:
a, b
– a secret key belonging to the key space of this affine cipher. This key must be an element of \(\ZZ/n\ZZ \times \ZZ/n\ZZ\) such that \(\gcd(a,n) = 1\) with \(n\) being the size of the ciphertext and plaintext spaces.P
– a string of plaintext; possibly an empty string. Characters in this string must be encoded using one of the supported alphabets. See the methodencoding()
for more information.
OUTPUT:
The ciphertext corresponding to the plaintext
P
.
EXAMPLES:
Encryption over the capital letters of the English alphabet:
sage: A = AffineCryptosystem(AlphabeticStrings()) sage: a, b = (3, 6) sage: P = A.encoding("Affine ciphers work with linear functions.") sage: A.enciphering(a, b, P) GVVETSMEZBSFIUWFKUELBNETSGFVOTMLEWTI
Now work through the previous example using functional notation:
sage: A = AffineCryptosystem(AlphabeticStrings()) sage: a, b = (3, 6) sage: P = A.encoding("Affine ciphers work with linear functions.") sage: E = A(a, b); E Affine cipher on Free alphabetic string monoid on A-Z sage: E(P) GVVETSMEZBSFIUWFKUELBNETSGFVOTMLEWTI
If the plaintext is an empty string, then the ciphertext is also an empty string regardless of the value of the secret key:
sage: a, b = A.random_key() sage: A.enciphering(a, b, A.encoding("")) sage: A.enciphering(a, b, A.encoding(" "))
- encoding(S)#
The encoding of the string
S
over the string monoid of this affine cipher. For example, if the string monoid of this cryptosystem isAlphabeticStringMonoid
, then the encoding ofS
would be its upper-case equivalent stripped of all non-alphabetic characters. Only the following alphabet is supported for the affine cipher:capital letters of the English alphabet as implemented in
AlphabeticStrings()
INPUT:
S
– a string, possibly empty.
OUTPUT:
The encoding of
S
over the string monoid of this cryptosystem. IfS
is an empty string, return an empty string.
EXAMPLES:
Encoding over the upper-case letters of the English alphabet:
sage: A = AffineCryptosystem(AlphabeticStrings()) sage: A.encoding("Affine cipher over capital letters of the English alphabet.") AFFINECIPHEROVERCAPITALLETTERSOFTHEENGLISHALPHABET
The argument
S
can be an empty string, in which case an empty string is returned:sage: AffineCryptosystem(AlphabeticStrings()).encoding("")
- inverse_key(a, b)#
The inverse key corresponding to the secret key \((a,b)\). If \(p\) is a plaintext character so that \(p \in \ZZ/n\ZZ\) and \(n\) is the alphabet size, then the ciphertext \(c\) corresponding to \(p\) is
\[c \equiv ap + b \pmod{n}\]As \((a,b)\) is a key, then the multiplicative inverse \(a^{-1}\) exists and the original plaintext can be recovered as follows
\[p \equiv a^{-1} (c - b) \pmod{n} \equiv a^{-1}c + a^{-1}(-b) \pmod{n}\]Therefore the ordered pair \((a^{-1}, -ba^{-1})\) is the inverse key corresponding to \((a,b)\).
INPUT:
a, b
– a secret key for this affine cipher. The ordered pair \((a,b)\) must be an element of \(\ZZ/n\ZZ \times \ZZ/n\ZZ\) such that \(\gcd(a,n) = 1\).
OUTPUT:
The inverse key \((a^{-1}, -ba^{-1})\) corresponding to \((a,b)\).
EXAMPLES:
sage: A = AffineCryptosystem(AlphabeticStrings()) sage: a, b = (1, 2) sage: A.inverse_key(a, b) (1, 24) sage: A.inverse_key(3, 2) (9, 8)
Suppose that the plaintext and ciphertext spaces are the capital letters of the English alphabet so that \(n = 26\). If \(\varphi(n)\) is the Euler phi function of \(n\), then there are \(\varphi(n)\) integers \(0 \leq a < n\) that are relatively prime to \(n\). For the capital letters of the English alphabet, there are 12 such integers relatively prime to \(n\):
sage: euler_phi(A.alphabet_size()) 12
And here is a list of those integers:
sage: n = A.alphabet_size() sage: L = [i for i in range(n) if gcd(i, n) == 1]; L [1, 3, 5, 7, 9, 11, 15, 17, 19, 21, 23, 25]
Then a secret key \((a,b)\) of this shift cryptosystem is such that \(a\) is an element of the list
L
in the last example. Any inverse key \((A, B)\) corresponding to \((a,b)\) is such that \(A\) is also in the listL
above:sage: a, b = (3, 9) sage: a in L True sage: aInv, bInv = A.inverse_key(a, b) sage: aInv, bInv (9, 23) sage: aInv in L True
- random_key()#
Generate a random key within the key space of this affine cipher. The generated secret key is an ordered pair \((a, b) \in \ZZ/n\ZZ \times \ZZ/n\ZZ\) with \(n\) being the size of the cipher domain and \(\gcd(a, n) = 1\). Let \(\varphi(n)\) denote the Euler phi function of \(n\). Then the affine cipher has \(n \cdot \varphi(n)\) possible keys (see page 10 of [Sti2006]).
OUTPUT:
A random key within the key space of this affine cryptosystem. The output key is an ordered pair \((a,b)\).
EXAMPLES:
sage: A = AffineCryptosystem(AlphabeticStrings()) sage: A.random_key() # random (17, 25)
If \((a,b)\) is a secret key and \(n\) is the size of the plaintext and ciphertext alphabets, then \(\gcd(a, n) = 1\):
sage: a, b = A.random_key() sage: n = A.alphabet_size() sage: gcd(a, n) 1
- rank_by_chi_square(C, pdict)#
Use the chi-square statistic to rank all possible keys. Currently, this method only applies to the capital letters of the English alphabet.
ALGORITHM:
Consider a non-empty alphabet \(A\) consisting of \(n\) elements, and let \(C\) be a ciphertext encoded using elements of \(A\). The plaintext \(P\) corresponding to \(C\) is also encoded using elements of \(A\). Let \(M\) be a candidate decipherment of \(C\), i.e. \(M\) is the result of attempting to decrypt \(C\) using a key \((a,b)\) which is not necessarily the same key used to encrypt \(P\). Suppose \(F_A(e)\) is the characteristic frequency probability of \(e \in A\) and let \(F_M(e)\) be the message frequency probability with respect to \(M\). The characteristic frequency probability distribution of an alphabet is the expected frequency probability distribution for that alphabet. The message frequency probability distribution of \(M\) provides a distribution of the ratio of character occurrences over message length. One can interpret the characteristic frequency probability \(F_A(e)\) as the expected probability, while the message frequency probability \(F_M(e)\) is the observed probability. If \(M\) is of length \(L\), then the observed frequency of \(e \in A\) is
\[O_M(e) = F_M(e) \cdot L\]and the expected frequency of \(e \in A\) is
\[E_A(e) = F_A(e) \cdot L\]The chi-square rank \(R_{\chi^2}(M)\) of \(M\) corresponding to a key \((a,b) \in \ZZ/n\ZZ \times \ZZ/n\ZZ\) is given by
\[R_{\chi^2}(M) = \sum_{e \in A} \frac {\big( O_M(e) - E_A(e) \big)^2} {E_A(e)}\]Cryptanalysis by exhaustive key search produces a candidate decipherment \(M_{a,b}\) for each possible key \((a,b)\). For a set \(D = \big\{M_{a_1,b_1}, M_{a_2,b_2}, \dots, M_{a_k,b_k} \big\}\) of all candidate decipherments corresponding to a ciphertext \(C\), the smaller is the rank \(R_{\chi^2}(M_{a_i,b_i})\) the more likely that \((a_i,b_i)\) is the secret key. This key ranking method is based on the Pearson chi-square test [PearsonTest].
INPUT:
C
– The ciphertext, a non-empty string. The ciphertext must be encoded using the upper-case letters of the English alphabet.pdict
– A dictionary of key, possible plaintext pairs. This should be the output ofbrute_force()
withranking="none"
.
OUTPUT:
A list ranking the most likely keys first. Each element of the list is a tuple of key, possible plaintext pairs.
EXAMPLES:
Use the chi-square statistic to rank all possible keys and their corresponding decipherment:
sage: A = AffineCryptosystem(AlphabeticStrings()) sage: a, b = (3, 7) sage: P = A.encoding("Line.") sage: C = A.enciphering(a, b, P) sage: Plist = A.brute_force(C) sage: Rank = A.rank_by_chi_square(C, Plist) sage: Rank[:10] # display only the top 10 candidate keys [((1, 1), NETS), ((3, 7), LINE), ((17, 20), STAD), ((5, 2), SLOT), ((5, 5), HADI), ((9, 25), TSLI), ((17, 15), DELO), ((15, 6), ETUN), ((21, 8), ELID), ((7, 17), HCTE)]
As more ciphertext is available, the reliability of the chi-square ranking function increases:
sage: A = AffineCryptosystem(AlphabeticStrings()) sage: a, b = (11, 24) sage: P = A.encoding("Longer message is more information for cryptanalysis.") sage: C = A.enciphering(a, b, P) sage: Plist = A.brute_force(C) sage: Rank = A.rank_by_chi_square(C, Plist) sage: Rank[:10] # display only the top 10 candidate keys [((11, 24), LONGERMESSAGEISMOREINFORMATIONFORCRYPTANALYSIS), ((17, 9), INURFSBFLLHRFDLBNSFDUYNSBHEDNUYNSTSVGEHUHIVLDL), ((9, 18), RMFIUHYUOOSIUWOYMHUWFBMHYSVWMFBMHGHETVSFSREOWO), ((15, 12), VSTACPUCOOGACYOUSPCYTBSPUGNYSTBSPEPIRNGTGVIOYO), ((3, 22), PAFOYLKYGGSOYEGKALYEFTALKSBEAFTALILCVBSFSPCGEG), ((25, 3), OHSRNADNPPFRNVPDHANVSCHADFEVHSCHAJABWEFSFOBPVP), ((7, 25), GHYNVIPVRRLNVFRPHIVFYEHIPLAFHYEHIDITQALYLGTRFR), ((5, 2), NEHCIVKISSUCIWSKEVIWHFEVKUPWEHFEVOVABPUHUNASWS), ((15, 25), IFGNPCHPBBTNPLBHFCPLGOFCHTALFGOFCRCVEATGTIVBLB), ((9, 6), BWPSERIEYYCSEGYIWREGPLWRICFGWPLWRQRODFCPCBOYGY)]
- rank_by_squared_differences(C, pdict)#
Use the squared-differences measure to rank all possible keys. Currently, this method only applies to the capital letters of the English alphabet.
ALGORITHM:
Consider a non-empty alphabet \(A\) consisting of \(n\) elements, and let \(C\) be a ciphertext encoded using elements of \(A\). The plaintext \(P\) corresponding to \(C\) is also encoded using elements of \(A\). Let \(M\) be a candidate decipherment of \(C\), i.e. \(M\) is the result of attempting to decrypt \(C\) using a key \((a,b)\) which is not necessarily the same key used to encrypt \(P\). Suppose \(F_A(e)\) is the characteristic frequency probability of \(e \in A\) and let \(F_M(e)\) be the message frequency probability with respect to \(M\). The characteristic frequency probability distribution of an alphabet is the expected frequency probability distribution for that alphabet. The message frequency probability distribution of \(M\) provides a distribution of the ratio of character occurrences over message length. One can interpret the characteristic frequency probability \(F_A(e)\) as the expected probability, while the message frequency probability \(F_M(e)\) is the observed probability. If \(M\) is of length \(L\), then the observed frequency of \(e \in A\) is
\[O_M(e) = F_M(e) \cdot L\]and the expected frequency of \(e \in A\) is
\[E_A(e) = F_A(e) \cdot L\]The squared-differences, or residual sum of squares, rank \(R_{RSS}(M)\) of \(M\) corresponding to a key \((a,b) \in \ZZ/n\ZZ \times \ZZ/n\ZZ\) is given by
\[R_{RSS}(M) = \sum_{e \in A} \big( O_M(e) - E_A(e) \big)^2\]Cryptanalysis by exhaustive key search produces a candidate decipherment \(M_{a,b}\) for each possible key \((a,b)\). For a set \(D = \big\{M_{a_1,b_1}, M_{a_2,b_2}, \dots, M_{a_k,b_k} \big\}\) of all candidate decipherments corresponding to a ciphertext \(C\), the smaller is the rank \(R_{RSS}(M_{a_i,b_i})\) the more likely that \((a_i,b_i)\) is the secret key. This key ranking method is based on the residual sum of squares measure [RSS].
INPUT:
C
– The ciphertext, a non-empty string. The ciphertext must be encoded using the upper-case letters of the English alphabet.pdict
– A dictionary of key, possible plaintext pairs. This should be the output ofbrute_force()
withranking="none"
.
OUTPUT:
A list ranking the most likely keys first. Each element of the list is a tuple of key, possible plaintext pairs.
EXAMPLES:
Use the method of squared differences to rank all possible keys and their corresponding decipherment:
sage: A = AffineCryptosystem(AlphabeticStrings()) sage: a, b = (3, 7) sage: P = A.encoding("Line.") sage: C = A.enciphering(a, b, P) sage: Plist = A.brute_force(C) sage: Rank = A.rank_by_squared_differences(C, Plist) sage: Rank[:10] # display only the top 10 candidate keys [((1, 1), NETS), ((15, 6), ETUN), ((7, 17), HCTE), ((3, 7), LINE), ((17, 15), DELO), ((9, 4), EDWT), ((9, 9), POHE), ((21, 8), ELID), ((17, 20), STAD), ((7, 18), SNEP)]
As more ciphertext is available, the reliability of the squared-differences ranking function increases:
sage: A = AffineCryptosystem(AlphabeticStrings()) sage: a, b = (11, 24) sage: P = A.encoding("Longer message is more information for cryptanalysis.") sage: C = A.enciphering(a, b, P) sage: Plist = A.brute_force(C) sage: Rank = A.rank_by_squared_differences(C, Plist) sage: Rank[:10] # display only the top 10 candidate keys [((11, 24), LONGERMESSAGEISMOREINFORMATIONFORCRYPTANALYSIS), ((9, 14), DYRUGTKGAAEUGIAKYTGIRNYTKEHIYRNYTSTQFHEREDQAIA), ((23, 24), DSNEUHIUMMAEUOMISHUONZSHIAROSNZSHKHQXRANADQMOM), ((23, 1), ETOFVIJVNNBFVPNJTIVPOATIJBSPTOATILIRYSBOBERNPN), ((21, 16), VEBGANYAQQOGAMQYENAMBDENYOTMEBDENUNIHTOBOVIQMQ), ((7, 12), TULAIVCIEEYAISECUVISLRUVCYNSULRUVQVGDNYLYTGESE), ((5, 20), ZQTOUHWUEEGOUIEWQHUITRQHWGBIQTRQHAHMNBGTGZMEIE), ((21, 8), JSPUOBMOEECUOAEMSBOAPRSBMCHASPRSBIBWVHCPCJWEAE), ((25, 7), SLWVREHRTTJVRZTHLERZWGLEHJIZLWGLENEFAIJWJSFTZT), ((25, 15), ATEDZMPZBBRDZHBPTMZHEOTMPRQHTEOTMVMNIQRERANBHB)]
- class sage.crypto.classical.HillCryptosystem(S, m)#
Bases:
SymmetricKeyCryptosystem
Create a Hill cryptosystem defined by the \(m\) x \(m\) matrix space over \(\ZZ / N \ZZ\), where \(N\) is the alphabet size of the string monoid
S
.INPUT:
S
- a string monoid over some alphabetm
- integer \(> 0\); the block length of matrices that specify block permutations
OUTPUT:
A Hill cryptosystem of block length
m
over the alphabetS
.
EXAMPLES:
sage: S = AlphabeticStrings() sage: E = HillCryptosystem(S,3) sage: E Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3 sage: R = IntegerModRing(26) sage: M = MatrixSpace(R,3,3) sage: A = M([[1,0,1],[0,1,1],[2,2,3]]) sage: A [1 0 1] [0 1 1] [2 2 3] sage: e = E(A) sage: e Hill cipher on Free alphabetic string monoid on A-Z of block length 3 sage: e(S("LAMAISONBLANCHE")) JYVKSKQPELAYKPV
- block_length()#
The row or column dimension of a matrix specifying a block permutation. Encryption and decryption keys of a Hill cipher are square matrices, i.e. the row and column dimensions of an encryption or decryption key are the same. This row/column dimension is referred to as the block length.
OUTPUT:
The block length of an encryption/decryption key.
EXAMPLES:
sage: A = AlphabeticStrings() sage: n = randint(1, A.ngens() - 1) sage: H = HillCryptosystem(A, n) sage: H.block_length() == n True
- deciphering(A, C)#
Decrypt the ciphertext
C
using the keyA
.INPUT:
A
- a key within the key space of this Hill cipherC
- a string (possibly empty) over the string monoid of this Hill cipher
OUTPUT:
The plaintext corresponding to the ciphertext
C
.
EXAMPLES:
sage: H = HillCryptosystem(AlphabeticStrings(), 3) sage: K = H.random_key() sage: M = H.encoding("Good day, mate! How ya going?") sage: H.deciphering(K, H.enciphering(K, M)) == M True
- enciphering(A, M)#
Encrypt the plaintext
M
using the keyA
.INPUT:
A
- a key within the key space of this Hill cipherM
- a string (possibly empty) over the string monoid of this Hill cipher.
OUTPUT:
The ciphertext corresponding to the plaintext
M
.
EXAMPLES:
sage: H = HillCryptosystem(AlphabeticStrings(), 3) sage: K = H.random_key() sage: M = H.encoding("Good day, mate! How ya going?") sage: H.deciphering(K, H.enciphering(K, M)) == M True
- encoding(M)#
The encoding of the string
M
over the string monoid of this Hill cipher. For example, if the string monoid of this Hill cipher isAlphabeticStringMonoid
, then the encoding ofM
would be its upper-case equivalent stripped of all non-alphabetic characters.INPUT:
M
- a string, possibly empty
OUTPUT:
The encoding of
M
over the string monoid of this Hill cipher.
EXAMPLES:
sage: M = "The matrix cipher by Lester S. Hill." sage: A = AlphabeticStrings() sage: H = HillCryptosystem(A, 7) sage: H.encoding(M) == A.encoding(M) True
- inverse_key(A)#
The inverse key corresponding to the key
A
.INPUT:
A
- an invertible matrix of the key space of this Hill cipher
OUTPUT:
The inverse matrix of
A
.
EXAMPLES:
sage: S = AlphabeticStrings() sage: E = HillCryptosystem(S,3) sage: A = E.random_key() sage: B = E.inverse_key(A) sage: M = S("LAMAISONBLANCHE") sage: e = E(A) sage: c = E(B) sage: c(e(M)) LAMAISONBLANCHE
- random_key()#
A random key within the key space of this Hill cipher. That is, generate a random \(m\) x \(m\) matrix to be used as a block permutation, where \(m\) is the block length of this Hill cipher. If \(n\) is the size of the cryptosystem alphabet, then there are \(n^{m^2}\) possible keys. However the number of valid keys, i.e. invertible \(m\) x \(m\) square matrices, is smaller than \(n^{m^2}\).
OUTPUT:
A random key within the key space of this Hill cipher.
EXAMPLES:
sage: A = AlphabeticStrings() sage: n = 3 sage: H = HillCryptosystem(A, n) sage: K = H.random_key() sage: Ki = H.inverse_key(K) sage: M = "LAMAISONBLANCHE" sage: e = H(K) sage: d = H(Ki) sage: d(e(A(M))) == A(M) True
- class sage.crypto.classical.ShiftCryptosystem(A)#
Bases:
SymmetricKeyCryptosystem
Create a shift cryptosystem.
Let \(A = \{ a_0, a_1, a_2, \dots, a_{n-1} \}\) be a non-empty alphabet consisting of \(n\) unique elements. Define a mapping \(f : A \longrightarrow \ZZ/ n\ZZ\) from the alphabet \(A\) to the set \(\ZZ / n\ZZ\) of integers modulo \(n\), given by \(f(a_i) = i\). Thus we can identify each element of the alphabet \(A\) with a unique integer \(0 \leq i < n\). A key of the shift cipher is an integer \(0 \leq k < n\). Therefore the key space is \(\ZZ / n\ZZ\). Since we assume that \(A\) does not have repeated elements, the mapping \(f : A \longrightarrow \ZZ/ n\ZZ\) is bijective. Encryption works by moving along the alphabet by \(k\) positions, with wrap around. Decryption reverses the process by moving backwards by \(k\) positions, with wrap around. More generally, let \(k\) be a secret key, i.e. an element of the key space, and let \(p\) be a plaintext character and consequently \(p \in \ZZ / n\ZZ\). Then the ciphertext character \(c\) corresponding to \(p\) is given by
\[c \equiv p + k \pmod{n}\]Similarly, given a ciphertext character \(c \in \ZZ / n\ZZ\) and a secret key \(k\), we can recover the corresponding plaintext character as follows:
\[p \equiv c - k \pmod{n}\]Use the bijection \(f : A \longrightarrow \ZZ/ n\ZZ\) to convert \(c\) and \(p\) back to elements of the alphabet \(A\). Currently, the following alphabets are supported for the shift cipher:
capital letters of the English alphabet as implemented in
AlphabeticStrings()
the alphabet consisting of the hexadecimal number system as implemented in
HexadecimalStrings()
the alphabet consisting of the binary number system as implemented in
BinaryStrings()
EXAMPLES:
Some examples illustrating encryption and decryption over various alphabets. Here is an example over the upper-case letters of the English alphabet:
sage: S = ShiftCryptosystem(AlphabeticStrings()); S Shift cryptosystem on Free alphabetic string monoid on A-Z sage: P = S.encoding("The shift cryptosystem generalizes the Caesar cipher.") sage: P THESHIFTCRYPTOSYSTEMGENERALIZESTHECAESARCIPHER sage: K = 7 sage: C = S.enciphering(K, P); C AOLZOPMAJYFWAVZFZALTNLULYHSPGLZAOLJHLZHYJPWOLY sage: S.deciphering(K, C) THESHIFTCRYPTOSYSTEMGENERALIZESTHECAESARCIPHER sage: S.deciphering(K, C) == P True
The previous example can also be done as follows:
sage: S = ShiftCryptosystem(AlphabeticStrings()) sage: P = S.encoding("The shift cryptosystem generalizes the Caesar cipher.") sage: K = 7 sage: E = S(K); E Shift cipher on Free alphabetic string monoid on A-Z sage: C = E(P); C AOLZOPMAJYFWAVZFZALTNLULYHSPGLZAOLJHLZHYJPWOLY sage: D = S(S.inverse_key(K)); D Shift cipher on Free alphabetic string monoid on A-Z sage: D(C) == P True sage: D(C) == P == D(E(P)) True
Over the hexadecimal number system:
sage: S = ShiftCryptosystem(HexadecimalStrings()); S Shift cryptosystem on Free hexadecimal string monoid sage: P = S.encoding("Encryption & decryption shifts along the alphabet."); P 456e6372797074696f6e20262064656372797074696f6e2073686966747320616c6f6e672074686520616c7068616265742e sage: K = 5 sage: C = S.enciphering(K, P); C 9ab3b8c7cec5c9beb4b3757b75b9bab8c7cec5c9beb4b375c8bdbebbc9c875b6b1b4b3bc75c9bdba75b6b1c5bdb6b7bac973 sage: S.deciphering(K, C) 456e6372797074696f6e20262064656372797074696f6e2073686966747320616c6f6e672074686520616c7068616265742e sage: S.deciphering(K, C) == P True
And over the binary number system:
sage: S = ShiftCryptosystem(BinaryStrings()); S Shift cryptosystem on Free binary string monoid sage: P = S.encoding("The binary alphabet is very insecure."); P<PHONE_NUMBER>1010000110010100100000011000100110100101101110011000010111001001111001001000000110000101101100011100000110100001100001011000100110010101110100001000000110100101110011001000000111011001100101011100100111100100100000011010010110111001110011011001010110001101110101011100100110010100101110 sage: K = 1 sage: C = S.enciphering(K, P); C<PHONE_NUMBER>0101111001101011011111100111011001011010010001100111101000110110000110110111111001111010010011100011111001011110011110100111011001101010001011110111111001011010001100110111111000100110011010100011011000011011011111100101101001000110001100100110101001110010001010100011011001101011010001 sage: S.deciphering(K, C)<PHONE_NUMBER>1010000110010100100000011000100110100101101110011000010111001001111001001000000110000101101100011100000110100001100001011000100110010101110100001000000110100101110011001000000111011001100101011100100111100100100000011010010110111001110011011001010110001101110101011100100110010100101110 sage: S.deciphering(K, C) == P True
A shift cryptosystem with key \(k = 3\) is commonly referred to as the Caesar cipher. Create a Caesar cipher over the upper-case letters of the English alphabet:
sage: caesar = ShiftCryptosystem(AlphabeticStrings()) sage: K = 3 sage: P = caesar.encoding("abcdef"); P ABCDEF sage: C = caesar.enciphering(K, P); C DEFGHI sage: caesar.deciphering(K, C) == P True
Generate a random key for encryption and decryption:
sage: S = ShiftCryptosystem(AlphabeticStrings()) sage: P = S.encoding("Shift cipher with a random key.") sage: K = S.random_key() sage: C = S.enciphering(K, P) sage: S.deciphering(K, C) == P True
Decrypting with the key
K
is equivalent to encrypting with its corresponding inverse key:sage: S.enciphering(S.inverse_key(K), C) == P True
- brute_force(C, ranking='none')#
Attempt a brute force cryptanalysis of the ciphertext
C
.INPUT:
C
– A ciphertext over one of the supported alphabets of this shift cryptosystem. See the classShiftCryptosystem
for documentation on the supported alphabets.ranking
– (default"none"
) the method to use for ranking all possible keys. Ifranking="none"
, then do not use any ranking function. The following ranking functions are supported:"chisquare"
– the chi-square ranking function as implemented in the methodrank_by_chi_square()
."squared_differences"
– the squared differences ranking function as implemented in the methodrank_by_squared_differences()
.
OUTPUT:
All the possible plaintext sequences corresponding to the ciphertext
C
. This method effectively uses all the possible keys in this shift cryptosystem to decryptC
. The method is also referred to as exhaustive key search. The output is a dictionary of key, plaintext pairs.
EXAMPLES:
Cryptanalyze using all possible keys for various alphabets. Over the upper-case letters of the English alphabet:
sage: S = ShiftCryptosystem(AlphabeticStrings()) sage: P = S.encoding("The shift cryptosystem generalizes the Caesar cipher.") sage: K = 7 sage: C = S.enciphering(K, P) sage: Dict = S.brute_force(C) sage: for k in range(len(Dict)): ....: if Dict[k] == P: ....: print("key = " + str(k)) key = 7
Over the hexadecimal number system:
sage: S = ShiftCryptosystem(HexadecimalStrings()) sage: P = S.encoding("Encryption & decryption shifts along the alphabet.") sage: K = 5 sage: C = S.enciphering(K, P) sage: Dict = S.brute_force(C) sage: for k in range(len(Dict)): ....: if Dict[k] == P: ....: print("key = " + str(k)) key = 5
And over the binary number system:
sage: S = ShiftCryptosystem(BinaryStrings()) sage: P = S.encoding("The binary alphabet is very insecure.") sage: K = 1 sage: C = S.enciphering(K, P) sage: Dict = S.brute_force(C) sage: for k in range(len(Dict)): ....: if Dict[k] == P: ....: print("key = " + str(k)) key = 1
Don’t use any ranking functions, i.e.
ranking="none"
:sage: S = ShiftCryptosystem(AlphabeticStrings()) sage: P = S.encoding("Shifting using modular arithmetic.") sage: K = 8 sage: C = S.enciphering(K, P) sage: pdict = S.brute_force(C) sage: sorted(pdict.items()) [(0, APQNBQVOCAQVOUWLCTIZIZQBPUMBQK), (1, ZOPMAPUNBZPUNTVKBSHYHYPAOTLAPJ), (2, YNOLZOTMAYOTMSUJARGXGXOZNSKZOI), (3, XMNKYNSLZXNSLRTIZQFWFWNYMRJYNH), (4, WLMJXMRKYWMRKQSHYPEVEVMXLQIXMG), (5, VKLIWLQJXVLQJPRGXODUDULWKPHWLF), (6, UJKHVKPIWUKPIOQFWNCTCTKVJOGVKE), (7, TIJGUJOHVTJOHNPEVMBSBSJUINFUJD), (8, SHIFTINGUSINGMODULARARITHMETIC), (9, RGHESHMFTRHMFLNCTKZQZQHSGLDSHB), (10, QFGDRGLESQGLEKMBSJYPYPGRFKCRGA), (11, PEFCQFKDRPFKDJLARIXOXOFQEJBQFZ), (12, ODEBPEJCQOEJCIKZQHWNWNEPDIAPEY), (13, NCDAODIBPNDIBHJYPGVMVMDOCHZODX), (14, MBCZNCHAOMCHAGIXOFULULCNBGYNCW), (15, LABYMBGZNLBGZFHWNETKTKBMAFXMBV), (16, KZAXLAFYMKAFYEGVMDSJSJALZEWLAU), (17, JYZWKZEXLJZEXDFULCRIRIZKYDVKZT), (18, IXYVJYDWKIYDWCETKBQHQHYJXCUJYS), (19, HWXUIXCVJHXCVBDSJAPGPGXIWBTIXR), (20, GVWTHWBUIGWBUACRIZOFOFWHVASHWQ), (21, FUVSGVATHFVATZBQHYNENEVGUZRGVP), (22, ETURFUZSGEUZSYAPGXMDMDUFTYQFUO), (23, DSTQETYRFDTYRXZOFWLCLCTESXPETN), (24, CRSPDSXQECSXQWYNEVKBKBSDRWODSM), (25, BQROCRWPDBRWPVXMDUJAJARCQVNCRL)]
Use the chi-square ranking function, i.e.
ranking="chisquare"
:sage: S.brute_force(C, ranking="chisquare") [(8, SHIFTINGUSINGMODULARARITHMETIC), (14, MBCZNCHAOMCHAGIXOFULULCNBGYNCW), (20, GVWTHWBUIGWBUACRIZOFOFWHVASHWQ), (13, NCDAODIBPNDIBHJYPGVMVMDOCHZODX), (1, ZOPMAPUNBZPUNTVKBSHYHYPAOTLAPJ), (23, DSTQETYRFDTYRXZOFWLCLCTESXPETN), (10, QFGDRGLESQGLEKMBSJYPYPGRFKCRGA), (6, UJKHVKPIWUKPIOQFWNCTCTKVJOGVKE), (22, ETURFUZSGEUZSYAPGXMDMDUFTYQFUO), (15, LABYMBGZNLBGZFHWNETKTKBMAFXMBV), (12, ODEBPEJCQOEJCIKZQHWNWNEPDIAPEY), (21, FUVSGVATHFVATZBQHYNENEVGUZRGVP), (16, KZAXLAFYMKAFYEGVMDSJSJALZEWLAU), (25, BQROCRWPDBRWPVXMDUJAJARCQVNCRL), (9, RGHESHMFTRHMFLNCTKZQZQHSGLDSHB), (24, CRSPDSXQECSXQWYNEVKBKBSDRWODSM), (3, XMNKYNSLZXNSLRTIZQFWFWNYMRJYNH), (5, VKLIWLQJXVLQJPRGXODUDULWKPHWLF), (7, TIJGUJOHVTJOHNPEVMBSBSJUINFUJD), (2, YNOLZOTMAYOTMSUJARGXGXOZNSKZOI), (18, IXYVJYDWKIYDWCETKBQHQHYJXCUJYS), (4, WLMJXMRKYWMRKQSHYPEVEVMXLQIXMG), (11, PEFCQFKDRPFKDJLARIXOXOFQEJBQFZ), (19, HWXUIXCVJHXCVBDSJAPGPGXIWBTIXR), (0, APQNBQVOCAQVOUWLCTIZIZQBPUMBQK), (17, JYZWKZEXLJZEXDFULCRIRIZKYDVKZT)]
Use the squared differences ranking function, i.e.
ranking="squared_differences"
:sage: S.brute_force(C, ranking="squared_differences") [(8, SHIFTINGUSINGMODULARARITHMETIC), (23, DSTQETYRFDTYRXZOFWLCLCTESXPETN), (12, ODEBPEJCQOEJCIKZQHWNWNEPDIAPEY), (2, YNOLZOTMAYOTMSUJARGXGXOZNSKZOI), (9, RGHESHMFTRHMFLNCTKZQZQHSGLDSHB), (7, TIJGUJOHVTJOHNPEVMBSBSJUINFUJD), (21, FUVSGVATHFVATZBQHYNENEVGUZRGVP), (22, ETURFUZSGEUZSYAPGXMDMDUFTYQFUO), (1, ZOPMAPUNBZPUNTVKBSHYHYPAOTLAPJ), (16, KZAXLAFYMKAFYEGVMDSJSJALZEWLAU), (20, GVWTHWBUIGWBUACRIZOFOFWHVASHWQ), (24, CRSPDSXQECSXQWYNEVKBKBSDRWODSM), (14, MBCZNCHAOMCHAGIXOFULULCNBGYNCW), (13, NCDAODIBPNDIBHJYPGVMVMDOCHZODX), (3, XMNKYNSLZXNSLRTIZQFWFWNYMRJYNH), (10, QFGDRGLESQGLEKMBSJYPYPGRFKCRGA), (15, LABYMBGZNLBGZFHWNETKTKBMAFXMBV), (6, UJKHVKPIWUKPIOQFWNCTCTKVJOGVKE), (11, PEFCQFKDRPFKDJLARIXOXOFQEJBQFZ), (25, BQROCRWPDBRWPVXMDUJAJARCQVNCRL), (17, JYZWKZEXLJZEXDFULCRIRIZKYDVKZT), (19, HWXUIXCVJHXCVBDSJAPGPGXIWBTIXR), (4, WLMJXMRKYWMRKQSHYPEVEVMXLQIXMG), (0, APQNBQVOCAQVOUWLCTIZIZQBPUMBQK), (18, IXYVJYDWKIYDWCETKBQHQHYJXCUJYS), (5, VKLIWLQJXVLQJPRGXODUDULWKPHWLF)]
- deciphering(K, C)#
Decrypt the ciphertext
C
with the keyK
using shift cipher decryption.INPUT:
K
– a secret key; a key belonging to the key space of this shift cipher. This key is an integer \(k\) satisfying the inequality \(0 \leq k < n\), where \(n\) is the size of the cipher domain.C
– a string of ciphertext; possibly an empty string. Characters in this string must be encoded using one of the supported alphabets. See the methodencoding()
for more information.
OUTPUT:
The plaintext corresponding to the ciphertext
C
.
EXAMPLES:
Let’s perform decryption over the supported alphabets. Here is decryption over the capital letters of the English alphabet:
sage: S = ShiftCryptosystem(AlphabeticStrings()) sage: P = S.encoding("Stop shifting me."); P STOPSHIFTINGME sage: K = 13 sage: C = S.enciphering(K, P); C FGBCFUVSGVATZR sage: S.deciphering(K, C) == P True
Decryption over the hexadecimal number system:
sage: S = ShiftCryptosystem(HexadecimalStrings()) sage: P = S.encoding("Shift me now."); P<PHONE_NUMBER>206d65206e6f772e sage: K = 7 sage: C = S.enciphering(K, P); C cadfd0ddeb97d4dc97d5d6ee95 sage: S.deciphering(K, C) == P True
Decryption over the binary number system:
sage: S = ShiftCryptosystem(BinaryStrings()) sage: P = S.encoding("OK, enough shifting."); P<PHONE_NUMBER>001011001011000010000001100101011011100110111101110101011001110110100000100000011100110110100001101001011001100111010001101001011011100110011100101110 sage: K = 1 sage: C = S.enciphering(K, P); C<PHONE_NUMBER>110100110100111101111110011010100100011001000010001010100110001001011111011111100011001001011110010110100110011000101110010110100100011001100011010001 sage: S.deciphering(K, C) == P True
- enciphering(K, P)#
Encrypt the plaintext
P
with the keyK
using shift cipher encryption.INPUT:
K
– a key belonging to the key space of this shift cipher. This key is an integer \(k\) satisfying the inequality \(0 \leq k < n\), where \(n\) is the size of the cipher domain.P
– a string of plaintext; possibly an empty string. Characters in this string must be encoded using one of the supported alphabets. See the methodencoding()
for more information.
OUTPUT:
The ciphertext corresponding to the plaintext
P
.
EXAMPLES:
Let’s perform encryption over the supported alphabets. Here is encryption over the capital letters of the English alphabet:
sage: S = ShiftCryptosystem(AlphabeticStrings()) sage: P = S.encoding("Shift your gear."); P SHIFTYOURGEAR sage: K = 3 sage: S.enciphering(K, P) VKLIWBRXUJHDU
Encryption over the hexadecimal number system:
sage: S = ShiftCryptosystem(HexadecimalStrings()) sage: P = S.encoding("Capitalize with the shift key."); P<PHONE_NUMBER>616c697a65207769746820746865207368696674206b65792e sage: K = 5 sage: S.enciphering(K, P) 98b6c5bec9b6b1becfba75ccbec9bd75c9bdba75c8bdbebbc975b0bace73
Encryption over the binary number system:
sage: S = ShiftCryptosystem(BinaryStrings()) sage: P = S.encoding("Don't shift."); P<PHONE_NUMBER>10111101101110001001110111010000100000011100110110100001101001011001100111010000101110 sage: K = 1 sage: S.enciphering(K, P)<PHONE_NUMBER>01000010010001110110001000101111011111100011001001011110010110100110011000101111010001
- encoding(S)#
The encoding of the string
S
over the string monoid of this shift cipher. For example, if the string monoid of this cryptosystem isAlphabeticStringMonoid
, then the encoding ofS
would be its upper-case equivalent stripped of all non-alphabetic characters. The following alphabets are supported for the shift cipher:capital letters of the English alphabet as implemented in
AlphabeticStrings()
the alphabet consisting of the hexadecimal number system as implemented in
HexadecimalStrings()
the alphabet consisting of the binary number system as implemented in
BinaryStrings()
INPUT:
S
– a string, possibly empty.
OUTPUT:
The encoding of
S
over the string monoid of this cryptosystem. IfS
is an empty string, return an empty string.
EXAMPLES:
Encoding over the upper-case letters of the English alphabet:
sage: S = ShiftCryptosystem(AlphabeticStrings()) sage: S.encoding("Shift cipher on capital letters of the English alphabet.") SHIFTCIPHERONCAPITALLETTERSOFTHEENGLISHALPHABET
Encoding over the binary system:
sage: S = ShiftCryptosystem(BinaryStrings()) sage: S.encoding("Binary")<PHONE_NUMBER>10100101101110011000010111001001111001
Encoding over the hexadecimal system:
sage: S = ShiftCryptosystem(HexadecimalStrings()) sage: S.encoding("Over hexadecimal system.") 4f7665722068657861646563696d616c2073797374656d2e
The argument
S
can be an empty string, in which case an empty string is returned:sage: ShiftCryptosystem(AlphabeticStrings()).encoding("") sage: ShiftCryptosystem(HexadecimalStrings()).encoding("") sage: ShiftCryptosystem(BinaryStrings()).encoding("")
- inverse_key(K)#
The inverse key corresponding to the key
K
. For the shift cipher, the inverse key corresponding toK
is \(-K \bmod n\), where \(n > 0\) is the size of the cipher domain, i.e. the plaintext/ciphertext space. A key \(k\) of the shift cipher is an integer \(0 \leq k < n\). The key \(k = 0\) has no effect on either the plaintext or the ciphertext.INPUT:
K
– a key for this shift cipher. This must be an integer \(k\) such that \(0 \leq k < n\), where \(n\) is the size of the cipher domain.
OUTPUT:
The inverse key corresponding to
K
.
EXAMPLES:
Some random keys and their respective inverse keys:
sage: S = ShiftCryptosystem(AlphabeticStrings()) sage: key = S.random_key(); key # random 2 sage: S.inverse_key(key) # random 24 sage: S = ShiftCryptosystem(HexadecimalStrings()) sage: key = S.random_key(); key # random 12 sage: S.inverse_key(key) # random 4 sage: S = ShiftCryptosystem(BinaryStrings()) sage: key = S.random_key(); key # random 1 sage: S.inverse_key(key) # random 1 sage: key = S.random_key(); key # random 0 sage: S.inverse_key(key) # random 0
Regardless of the value of a key, the addition of the key and its inverse must be equal to the alphabet size. This relationship holds exactly when the value of the key is non-zero:
sage: S = ShiftCryptosystem(AlphabeticStrings()) sage: K = S.random_key() sage: while K == 0: ....: K = S.random_key() sage: invK = S.inverse_key(K) sage: K + invK == S.alphabet_size() True sage: invK + K == S.alphabet_size() True sage: K = S.random_key() sage: while K != 0: ....: K = S.random_key() sage: invK = S.inverse_key(K) sage: K + invK != S.alphabet_size() True sage: K; invK 0 0
- random_key()#
Generate a random key within the key space of this shift cipher. The generated key is an integer \(0 \leq k < n\) with \(n\) being the size of the cipher domain. Thus there are \(n\) possible keys in the key space, which is the set \(\ZZ / n\ZZ\). The key \(k = 0\) has no effect on either the plaintext or the ciphertext.
OUTPUT:
A random key within the key space of this shift cryptosystem.
EXAMPLES:
sage: S = ShiftCryptosystem(AlphabeticStrings()) sage: S.random_key() # random 18 sage: S = ShiftCryptosystem(BinaryStrings()) sage: S.random_key() # random 0 sage: S = ShiftCryptosystem(HexadecimalStrings()) sage: S.random_key() # random 5
Regardless of the value of a key, the addition of the key and its inverse must be equal to the alphabet size. This relationship holds exactly when the value of the key is non-zero:
sage: S = ShiftCryptosystem(AlphabeticStrings()) sage: K = S.random_key() sage: while K == 0: ....: K = S.random_key() sage: invK = S.inverse_key(K) sage: K + invK == S.alphabet_size() True sage: invK + K == S.alphabet_size() True sage: K = S.random_key() sage: while K != 0: ....: K = S.random_key() sage: invK = S.inverse_key(K) sage: K + invK != S.alphabet_size() True sage: K; invK 0 0
- rank_by_chi_square(C, pdict)#
Use the chi-square statistic to rank all possible keys. Currently, this method only applies to the capital letters of the English alphabet.
ALGORITHM:
Consider a non-empty alphabet \(A\) consisting of \(n\) elements, and let \(C\) be a ciphertext encoded using elements of \(A\). The plaintext \(P\) corresponding to \(C\) is also encoded using elements of \(A\). Let \(M\) be a candidate decipherment of \(C\), i.e. \(M\) is the result of attempting to decrypt \(C\) using a key \(k \in \ZZ/n\ZZ\) which is not necessarily the same key used to encrypt \(P\). Suppose \(F_A(e)\) is the characteristic frequency probability of \(e \in A\) and let \(F_M(e)\) be the message frequency probability with respect to \(M\). The characteristic frequency probability distribution of an alphabet is the expected frequency probability distribution for that alphabet. The message frequency probability distribution of \(M\) provides a distribution of the ratio of character occurrences over message length. One can interpret the characteristic frequency probability \(F_A(e)\) as the expected probability, while the message frequency probability \(F_M(e)\) is the observed probability. If \(M\) is of length \(L\), then the observed frequency of \(e \in A\) is
\[O_M(e) = F_M(e) \cdot L\]and the expected frequency of \(e \in A\) is
\[E_A(e) = F_A(e) \cdot L\]The chi-square rank \(R_{\chi^2}(M)\) of \(M\) corresponding to a key \(k \in \ZZ/n\ZZ\) is given by
\[R_{\chi^2}(M) = \sum_{e \in A} \frac {\big( O_M(e) - E_A(e) \big)^2} {E_A(e)}\]Cryptanalysis by exhaustive key search produces a candidate decipherment \(M_{k}\) for each possible key \(k \in \ZZ/n\ZZ\). For a set \(D = \big\{M_{k_1}, M_{k_2}, \dots, M_{k_r} \big\}\) of all candidate decipherments corresponding to a ciphertext \(C\), the smaller is the rank \(R_{\chi^2}(M_{k_i})\) the more likely that \(k_i\) is the secret key. This key ranking method is based on the Pearson chi-square test [PearsonTest].
INPUT:
C
– The ciphertext, a non-empty string. The ciphertext must be encoded using the upper-case letters of the English alphabet.pdict
– A dictionary of key, possible plaintext pairs. This should be the output ofbrute_force()
withranking="none"
.
OUTPUT:
A list ranking the most likely keys first. Each element of the list is a tuple of key, possible plaintext pairs.
EXAMPLES:
Use the chi-square statistic to rank all possible keys and their corresponding decipherment:
sage: S = ShiftCryptosystem(AlphabeticStrings()) sage: P = S.encoding("Shi."); P SHI sage: K = 5 sage: C = S.enciphering(K, P) sage: Pdict = S.brute_force(C) sage: S.rank_by_chi_square(C, Pdict) [(9, ODE), (5, SHI), (20, DST), (19, ETU), (21, CRS), (10, NCD), (25, YNO), (6, RGH), (12, LAB), (8, PEF), (1, WLM), (11, MBC), (18, FUV), (17, GVW), (2, VKL), (4, TIJ), (3, UJK), (0, XMN), (16, HWX), (15, IXY), (23, APQ), (24, ZOP), (22, BQR), (7, QFG), (13, KZA), (14, JYZ)]
As more ciphertext is available, the reliability of the chi-square ranking function increases:
sage: P = S.encoding("Shift cipher."); P SHIFTCIPHER sage: C = S.enciphering(K, P) sage: Pdict = S.brute_force(C) sage: S.rank_by_chi_square(C, Pdict) [(5, SHIFTCIPHER), (9, ODEBPYELDAN), (18, FUVSGPVCURE), (2, VKLIWFLSKHU), (20, DSTQENTASPC), (19, ETURFOUBTQD), (21, CRSPDMSZROB), (6, RGHESBHOGDQ), (7, QFGDRAGNFCP), (12, LABYMVBIAXK), (17, GVWTHQWDVSF), (24, ZOPMAJPWOLY), (1, WLMJXGMTLIV), (0, XMNKYHNUMJW), (11, MBCZNWCJBYL), (8, PEFCQZFMEBO), (25, YNOLZIOVNKX), (10, NCDAOXDKCZM), (3, UJKHVEKRJGT), (4, TIJGUDJQIFS), (22, BQROCLRYQNA), (16, HWXUIRXEWTG), (15, IXYVJSYFXUH), (14, JYZWKTZGYVI), (13, KZAXLUAHZWJ), (23, APQNBKQXPMZ)]
- rank_by_squared_differences(C, pdict)#
Use the squared-differences measure to rank all possible keys. Currently, this method only applies to the capital letters of the English alphabet.
ALGORITHM:
Consider a non-empty alphabet \(A\) consisting of \(n\) elements, and let \(C\) be a ciphertext encoded using elements of \(A\). The plaintext \(P\) corresponding to \(C\) is also encoded using elements of \(A\). Let \(M\) be a candidate decipherment of \(C\), i.e. \(M\) is the result of attempting to decrypt \(C\) using a key \(k \in \ZZ/n\ZZ\) which is not necessarily the same key used to encrypt \(P\). Suppose \(F_A(e)\) is the characteristic frequency probability of \(e \in A\) and let \(F_M(e)\) be the message frequency probability with respect to \(M\). The characteristic frequency probability distribution of an alphabet is the expected frequency probability distribution for that alphabet. The message frequency probability distribution of \(M\) provides a distribution of the ratio of character occurrences over message length. One can interpret the characteristic frequency probability \(F_A(e)\) as the expected probability, while the message frequency probability \(F_M(e)\) is the observed probability. If \(M\) is of length \(L\), then the observed frequency of \(e \in A\) is
\[O_M(e) = F_M(e) \cdot L\]and the expected frequency of \(e \in A\) is
\[E_A(e) = F_A(e) \cdot L\]The squared-differences, or residual sum of squares, rank \(R_{RSS}(M)\) of \(M\) corresponding to a key \(k \in \ZZ/n\ZZ\) is given by
\[R_{RSS}(M) = \sum_{e \in A} \big( O_M(e) - E_A(e) \big)^2\]Cryptanalysis by exhaustive key search produces a candidate decipherment \(M_{k}\) for each possible key \(k \in \ZZ/n\ZZ\). For a set \(D = \big\{M_{k_1}, M_{k_2}, \dots, M_{k_r} \big\}\) of all candidate decipherments corresponding to a ciphertext \(C\), the smaller is the rank \(R_{RSS}(M_{k_i})\) the more likely that \(k_i\) is the secret key. This key ranking method is based on the residual sum of squares measure [RSS].
INPUT:
C
– The ciphertext, a non-empty string. The ciphertext must be encoded using the upper-case letters of the English alphabet.pdict
– A dictionary of key, possible plaintext pairs. This should be the output ofbrute_force()
withranking="none"
.
OUTPUT:
A list ranking the most likely keys first. Each element of the list is a tuple of key, possible plaintext pairs.
EXAMPLES:
Use the method of squared differences to rank all possible keys and their corresponding decipherment:
sage: S = ShiftCryptosystem(AlphabeticStrings()) sage: P = S.encoding("Shi."); P SHI sage: K = 5 sage: C = S.enciphering(K, P) sage: Pdict = S.brute_force(C) sage: S.rank_by_squared_differences(C, Pdict) [(19, ETU), (9, ODE), (20, DST), (5, SHI), (8, PEF), (4, TIJ), (25, YNO), (21, CRS), (6, RGH), (10, NCD), (12, LAB), (23, APQ), (24, ZOP), (0, XMN), (13, KZA), (15, IXY), (1, WLM), (16, HWX), (22, BQR), (11, MBC), (18, FUV), (2, VKL), (17, GVW), (7, QFG), (3, UJK), (14, JYZ)]
As more ciphertext is available, the reliability of the squared differences ranking function increases:
sage: P = S.encoding("Shift cipher."); P SHIFTCIPHER sage: C = S.enciphering(K, P) sage: Pdict = S.brute_force(C) sage: S.rank_by_squared_differences(C, Pdict) [(20, DSTQENTASPC), (5, SHIFTCIPHER), (9, ODEBPYELDAN), (19, ETURFOUBTQD), (6, RGHESBHOGDQ), (16, HWXUIRXEWTG), (8, PEFCQZFMEBO), (21, CRSPDMSZROB), (22, BQROCLRYQNA), (25, YNOLZIOVNKX), (3, UJKHVEKRJGT), (18, FUVSGPVCURE), (4, TIJGUDJQIFS), (10, NCDAOXDKCZM), (7, QFGDRAGNFCP), (24, ZOPMAJPWOLY), (2, VKLIWFLSKHU), (12, LABYMVBIAXK), (17, GVWTHQWDVSF), (1, WLMJXGMTLIV), (13, KZAXLUAHZWJ), (0, XMNKYHNUMJW), (15, IXYVJSYFXUH), (14, JYZWKTZGYVI), (11, MBCZNWCJBYL), (23, APQNBKQXPMZ)]
- class sage.crypto.classical.SubstitutionCryptosystem(S)#
Bases:
SymmetricKeyCryptosystem
Create a substitution cryptosystem.
INPUT:
S
- a string monoid over some alphabet
OUTPUT:
A substitution cryptosystem over the alphabet
S
.
EXAMPLES:
sage: M = AlphabeticStrings() sage: E = SubstitutionCryptosystem(M) sage: E Substitution cryptosystem on Free alphabetic string monoid on A-Z sage: K = M([ 25-i for i in range(26) ]) sage: K ZYXWVUTSRQPONMLKJIHGFEDCBA sage: e = E(K) sage: m = M("THECATINTHEHAT") sage: e(m) GSVXZGRMGSVSZG
- deciphering(K, C)#
Decrypt the ciphertext
C
using the keyK
.INPUT:
K
- a key belonging to the key space of this substitution cipherC
- a string (possibly empty) over the string monoid of this cryptosystem.
OUTPUT:
The plaintext corresponding to the ciphertext
C
.
EXAMPLES:
sage: S = SubstitutionCryptosystem(AlphabeticStrings()) sage: K = S.random_key() sage: M = S.encoding("Don't substitute me!") sage: S.deciphering(K, S.enciphering(K, M)) == M True
- enciphering(K, M)#
Encrypt the plaintext
M
using the keyK
.INPUT:
K
- a key belonging to the key space of this substitution cipherM
- a string (possibly empty) over the string monoid of this cryptosystem.
OUTPUT:
The ciphertext corresponding to the plaintext
M
.
EXAMPLES:
sage: S = SubstitutionCryptosystem(AlphabeticStrings()) sage: K = S.random_key() sage: M = S.encoding("Don't substitute me.") sage: S.deciphering(K, S.enciphering(K, M)) == M True
- encoding(M)#
The encoding of the string
M
over the string monoid of this substitution cipher. For example, if the string monoid of this cryptosystem isAlphabeticStringMonoid
, then the encoding ofM
would be its upper-case equivalent stripped of all non-alphabetic characters.INPUT:
M
- a string, possibly empty
OUTPUT:
The encoding of
M
over the string monoid of this cryptosystem.
EXAMPLES:
sage: M = "Peter Pan(ning) for gold." sage: A = AlphabeticStrings() sage: S = SubstitutionCryptosystem(A) sage: S.encoding(M) == A.encoding(M) True
- inverse_key(K)#
The inverse key corresponding to the key
K
. The specified key is a permutation of the cryptosystem alphabet.INPUT:
K
- a key belonging to the key space of this cryptosystem
OUTPUT:
The inverse key of
K
.
EXAMPLES:
sage: S = AlphabeticStrings() sage: E = SubstitutionCryptosystem(S) sage: K = E.random_key() sage: L = E.inverse_key(K) sage: M = S("THECATINTHEHAT") sage: e = E(K) sage: c = E(L) sage: c(e(M)) THECATINTHEHAT
- random_key()#
Generate a random key within the key space of this substitution cipher. The generated key is a permutation of the cryptosystem alphabet. Let \(n\) be the length of the alphabet. Then there are \(n!\) possible keys in the key space.
OUTPUT:
A random key within the key space of this cryptosystem.
EXAMPLES:
sage: A = AlphabeticStrings() sage: S = SubstitutionCryptosystem(A) sage: K = S.random_key() sage: Ki = S.inverse_key(K) sage: M = "THECATINTHEHAT" sage: e = S(K) sage: d = S(Ki) sage: d(e(A(M))) == A(M) True
- class sage.crypto.classical.TranspositionCryptosystem(S, n)#
Bases:
SymmetricKeyCryptosystem
Create a transposition cryptosystem of block length
n
.INPUT:
S
- a string monoid over some alphabetn
- integer \(> 0\); a block length of a block permutation
OUTPUT:
A transposition cryptosystem of block length
n
over the alphabetS
.
EXAMPLES:
sage: S = AlphabeticStrings() sage: E = TranspositionCryptosystem(S,14) sage: E Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14 sage: K = [ 14-i for i in range(14) ] sage: K [14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] sage: e = E(K) sage: e(S("THECATINTHEHAT")) TAHEHTNITACEHT
- deciphering(K, C)#
Decrypt the ciphertext
C
using the keyK
.INPUT:
K
- a key belonging to the key space of this transposition cipherC
- a string (possibly empty) over the string monoid of this cryptosystem.
OUTPUT:
The plaintext corresponding to the ciphertext
C
.
EXAMPLES:
sage: T = TranspositionCryptosystem(AlphabeticStrings(), 14) sage: K = T.random_key() sage: M = T.encoding("The cat in the hat.") sage: T.deciphering(K, T.enciphering(K, M)) == M True
- enciphering(K, M)#
Encrypt the plaintext
M
using the keyK
.INPUT:
K
- a key belonging to the key space of this transposition cipherM
- a string (possibly empty) over the string monoid of this cryptosystem
OUTPUT:
The ciphertext corresponding to the plaintext
M
.
EXAMPLES:
sage: T = TranspositionCryptosystem(AlphabeticStrings(), 14) sage: K = T.random_key() sage: M = T.encoding("The cat in the hat.") sage: T.deciphering(K, T.enciphering(K, M)) == M True
- encoding(M)#
The encoding of the string
M
over the string monoid of this transposition cipher. For example, if the string monoid of this cryptosystem isAlphabeticStringMonoid
, then the encoding ofM
would be its upper-case equivalent stripped of all non-alphabetic characters.INPUT:
M
- a string, possibly empty
OUTPUT:
The encoding of
M
over the string monoid of this cryptosystem.
EXAMPLES:
sage: M = "Transposition cipher is not about matrix transpose." sage: A = AlphabeticStrings() sage: T = TranspositionCryptosystem(A, 11) sage: T.encoding(M) == A.encoding(M) True
- inverse_key(K, check=True)#
The inverse key corresponding to the key
K
.INPUT:
K
- a key belonging to the key space of this transposition ciphercheck
- bool (default:True
); check thatK
belongs to the key space of this cryptosystem.
OUTPUT:
The inverse key corresponding to
K
.
EXAMPLES:
sage: S = AlphabeticStrings() sage: E = TranspositionCryptosystem(S, 14) sage: K = E.random_key() sage: Ki = E.inverse_key(K) sage: e = E(K) sage: d = E(Ki) sage: M = "THECATINTHEHAT" sage: C = e(S(M)) sage: d(S(C)) == S(M) True
- random_key()#
Generate a random key within the key space of this transposition cryptosystem. Let \(n > 0\) be the block length of this cryptosystem. Then there are \(n!\) possible keys.
OUTPUT:
A random key within the key space of this cryptosystem.
EXAMPLES:
sage: S = AlphabeticStrings() sage: E = TranspositionCryptosystem(S, 14) sage: K = E.random_key() sage: Ki = E.inverse_key(K) sage: e = E(K) sage: d = E(Ki) sage: M = "THECATINTHEHAT" sage: C = e(S(M)) sage: d(S(C)) == S(M) True
- class sage.crypto.classical.VigenereCryptosystem(S, n)#
Bases:
SymmetricKeyCryptosystem
Create a Vigenere cryptosystem of block length
n
.INPUT:
S
– a string monoid over some alphabetn
- integer \(> 0\); block length of an encryption/decryption key
OUTPUT:
A Vigenere cryptosystem of block length
n
over the alphabetS
.
EXAMPLES:
sage: S = AlphabeticStrings() sage: E = VigenereCryptosystem(S,14) sage: E Vigenere cryptosystem on Free alphabetic string monoid on A-Z of period 14 sage: K = S('ABCDEFGHIJKLMN') sage: K ABCDEFGHIJKLMN sage: e = E(K) sage: e Cipher on Free alphabetic string monoid on A-Z sage: e(S("THECATINTHEHAT")) TIGFEYOUBQOSMG
- deciphering(K, C)#
Decrypt the ciphertext
C
using the keyK
.INPUT:
K
- a key belonging to the key space of this Vigenere cipherC
- a string (possibly empty) over the string monoid of this cryptosystem
OUTPUT:
The plaintext corresponding to the ciphertext
C
.
EXAMPLES:
sage: V = VigenereCryptosystem(AlphabeticStrings(), 24) sage: K = V.random_key() sage: M = V.encoding("Jack and Jill went up the hill.") sage: V.deciphering(K, V.enciphering(K, M)) == M True
- enciphering(K, M)#
Encrypt the plaintext
M
using the keyK
.INPUT:
K
- a key belonging to the key space of this Vigenere cipherM
- a string (possibly empty) over the string monoid of this cryptosystem
OUTPUT:
The ciphertext corresponding to the plaintext
M
.
EXAMPLES:
sage: V = VigenereCryptosystem(AlphabeticStrings(), 24) sage: K = V.random_key() sage: M = V.encoding("Jack and Jill went up the hill.") sage: V.deciphering(K, V.enciphering(K, M)) == M True
- encoding(M)#
The encoding of the string
M
over the string monoid of this Vigenere cipher. For example, if the string monoid of this cryptosystem isAlphabeticStringMonoid
, then the encoding ofM
would be its upper-case equivalent stripped of all non-alphabetic characters.INPUT:
M
- a string, possibly empty
OUTPUT:
The encoding of
M
over the string monoid of this cryptosystem.
EXAMPLES:
sage: A = AlphabeticStrings() sage: V = VigenereCryptosystem(A, 24) sage: M = "Jack and Jill went up the hill." sage: V.encoding(M) == A.encoding(M) True
- inverse_key(K)#
The inverse key corresponding to the key
K
.INPUT:
K
- a key within the key space of this Vigenere cryptosystem
OUTPUT:
The inverse key corresponding to
K
.
EXAMPLES:
sage: S = AlphabeticStrings() sage: E = VigenereCryptosystem(S,14) sage: K = E.random_key() sage: L = E.inverse_key(K) sage: M = S("THECATINTHEHAT") sage: e = E(K) sage: c = E(L) sage: c(e(M)) THECATINTHEHAT
- random_key()#
Generate a random key within the key space of this Vigenere cryptosystem. Let \(n > 0\) be the length of the cryptosystem alphabet and let \(m > 0\) be the block length of this cryptosystem. Then there are \(n^m\) possible keys.
OUTPUT:
A random key within the key space of this cryptosystem.
EXAMPLES:
sage: A = AlphabeticStrings() sage: V = VigenereCryptosystem(A, 14) sage: M = "THECATINTHEHAT" sage: K = V.random_key() sage: Ki = V.inverse_key(K) sage: e = V(K) sage: d = V(Ki) sage: d(e(A(M))) == A(M) True


Caleb Troughton
I am a multidisciplinary Software Engineer with over 17 years of industry experience, currently focused on internal platforms and developer tooling. From discovery to planning to shipping code, I love to own high impact solutions to problems Engineers face in delivering their products.
Work Experience
Mux: Technical Program Manager, Platform Engineering
12/2021 - 06/2023
- Driver of platform-led cross-team projects, including Kubernetes cluster migrations, the adoption of Vault as a secret store, GitOps tooling for cluster bootstrapping and core component management, and AWS Foundational Technical Reviews.
- Established agile processes with the Platform Engineering team during a transition to distinct squads focused on observability, infrastructure tooling, and developer experience.
Technologies
- Kubernetes
- CAPI + CAPA
- Vault
- Terraform
- Prometheus + Grafana + Jaeger
- Bazel
- Buildkite
- Argo CD + Workflows
New Relic: Product Manager
08/2020 - 12/2021
- Managed roadmap for multiple internal-facing teams, collectively responsible for build and deploy, datecenter operation tooling, Kubernetes infrastructure, cloud accounts and access, and production capacity automation.
- Responsible for automation initiatives across teams during migrations from DC/OS to Kubernetes, on-prem datacenters to cloud hosting, and from a large single-cluster to multi-cluster cellular production topology.
- Served as a "NERF", a rotation of senior leaders responsible for incident command in high severity production incidents.
Technologies
- Kubernetes
- Terraform
- Argo CD + Workflows
New Relic: Senior Software Engineer
02/2015 - 08/2020
- 4.5 years as a member of the Build & Deploy Tools team, responsible for internal platform tooling used across all Engineering teams. Our systems enabled thousands of microservices, frontend assets, and infrastructure as code projects to be continuously delivered to multiple production targets thousands of times each week.
- Simultaneously served 3 years as Technical Product Manager for the team, working with Engineering Managers, Product Managers, Program Managers, and other leaders to drive the team's roadmap.
- Architected a distributed plugin system for deploys to allow rapid experimentation and expansion of internal tooling to new systems.
- Led user interface development for our central internal deploy tool.
- 1 year as a member of the APM team focused on Service Maps, a tool for visualizing complex microservice architectures and their communication patterns.
Technologies
- Go
- JavaScript (React + Redux, Angular)
- Kubernetes
- Argo CD + Worklows + Events + Rollouts
- Jenkins
- Terraform + Atlantis
- Marathon + Mesos
- New Relic
- Ruby on Rails
- CSS (SASS)
Fat Arrow: Full Stack Engineer
04/2009 - 02/2015
Owner/operator of an independent consultant business with a wide range of projects from startup MVPs, to E-commerce platforms, to open source research and development using Ruby on Rails and various JavaScript frameworks. Client list available upon request.
Technologies
- Ruby on Rails
- JavaScript (Backbone)
- CSS
Rosetta: Front End Engineer
10/2006 - 02/2010
UI engineering on Blackberry and Apple accounts.
CADRC: Java Engineer
08/2005 - 10/2006
Interface development on cargo ship stowage planning software used by the Department of Defense.


--- title: Intro to CV and Python subtitle: Basic python tutorial part 2 notebook cover-img: /pages/c_01_intro_to_CV_and_Python/c_01_bigimg.jpg layout: notebook ---
Based on:
this git of Zhiya Zuo
&
tutorials from tutorialspoint
In the following examples, we show examples of comparison, if-else
loop, for
loop, and while
loop.
Python syntax for comparison is the same as our hand-written convention:
>
(>=
)<
(<=
)==
!=
3 == 5
72 >= 2
test_str = "test"
test_str == "test" # can also compare strings
sum_ =0
if sum_ == 0:
print("sum_ is 0")
elif sum_ < 0:
print("sum_ is less than 0")
else:
print("sum_ is above 0 and its value is " + str(sum_)) # Cast sum_ into string type.
Comparing strings are similar
store_name = 'Walmart'
if 'Wal' in store_name:
print("The store is not Walmart. It's " + store_name + ".")
else:
print("The store is Walmart.")
for letter in store_name:
print(letter)
range()
is a function to create integer sequences:
a_range = range(5)
print(a_range)
print("range(5) gives" + str(list(range(5)))) # By default starts from 0
print("range(1,9) gives: " + str(list(range(1, 9)))) # From 1 to 8 (Again the end index is exclusive.)
for index in range(len(store_name)): # length of a sequence
print("The %ith letter in store_name is: %s"%(index, store_name[index]))
x = [i for i in range(10)]
print(x)
a lot of cool things can be done in one line!
x = [i + 2 for i in range(10)]
print(x)
x = [i ** 2 for i in range(10) if i%2==0]
print(x)
x = 2
while x < 10:
print(x)
x = x + 1
store_name = 'Walmart'
index = 0
while True:
print(store_name[index])
index += 1 # a += b means a = a + b
if store_name[index] == "a":
print("End at a")
break # instead of setting flag to False, we can directly break out of the loop
print("Hello!") # This will NOT be run
continue
means get to the next iteration of loop. It will break the current iteration and continue to the next.
for letter in store_name:
if letter == "a":
continue # Not printing a
else:
print(letter)
def F(n): # bonus- what does this function do?
if n<0:
print("Incorrect input")
elif n==0:
return 0
elif n==1:
return 1
else:
return F(n-1)+F(n-2)
print(F(2))
print(F(3))
print(F(5))
print(F(7))
def geo_seq(a_1, q, n):
a_n = a_1 * (q ** (n-1))
S_n = (a_1 * (q ** n - 1)) / (q - 1)
return a_n, S_n
print(geo_seq(2, 2, 1)) # multiple outputs returns as a tuple
print(geo_seq(2, 2, 2))
print(geo_seq(2, 2, 2))
print(geo_seq(2, 2, 3)[1]) # get only second element
def geo_seq_optional_args(a_1, q=2, n=1):
a_n = a_1 * (q ** (n-1))
S_n = (a_1 * (q ** n - 1)) / (q - 1)
return a_n, S_n
print(geo_seq_optional_args(2))
print(geo_seq_optional_args(2, n=2))
class Employee:
# the function that is being called each time a new instance is created
def __init__(self, name="Jhon", salary=10000):
# per instance variables
self.name = name
self.salary = salary
def display_employee(self):
print("Name : " + self.name + ", Salary: "+ str(self.salary))
def change_salary(self, new_salary):
self.salary = new_salary
emp1 = Employee() #create new instance
emp1.display_employee()
emp2 = Employee("Bob", salary=20000) #create new instance
emp2.display_employee()
emp2.change_salary(30000)
emp2.display_employee()
# instance variables are also accessible - no such thing private/public vars
emp2.name = "Larry"
emp2.display_employee()
f = open("tmp1.csv", "w") # f is a file handler, while "w" is the mode (w for write)
for item in range(6):
f.write(str(item) + "\n")
f.close() # close the filer handler for security reasons.
Note that without the typecasting from int
to str
, an error will be raised.
A more commonly used way:
with open("tmp2.csv", "w") as f:
for item in range(4):
f.write(str(item))
f.write("\n")
# no need to close file, when out of 'with' scope the file closes automatically
Occasionally, we need to append new elements instead of overwriting existing files. In this case, we should use a
mode in our open
function:
with open("tmp2.csv", "a") as f: # 'a' == append to end of file
for item in range(15, 19):
f.write(str(item)+"\n")
f = open("tmp1.csv", "r") # this time, use read mode
contents = [item.strip("\n") for item in f] # list comprehension. This is the same as for-loop but more concise + stripping newline
print(contents)
f.close()
Also using with
:
with open("tmp2.csv", "r") as f:
print(f.readlines())
# delete the files...
import os
os.remove("tmp1.csv")
os.remove("tmp2.csv")
import math # use import to load a library
To use functions from the library, do: library_name.function_name
. For example, when we want to calculate the logarithm using a function from math
library, we can do math.log
x = 3
print("e^x = e^3 = %f"%math.exp(x))
print("log(x) = log(3) = %f"%math.log(x))
You can also import one specific function:
from math import exp # You can import a specific function
print(exp(x)) # This way, you don't need to use math.exp but just exp
Or all:
from math import * # Import all functions - not recommended do to overriding of functions
print(exp(x))
print(log(x)) # Before importing math, calling `exp` or `log` will raise errors
You can import a package with a shortened name:
import math as m
m.exp(3)
Depending on what you want to achieve, you may want to choose between importing a few or all (by *
) functions within a package.
There are times you'll want some advanced utility functions not provided by Python. There are many useful packages by developers.
We'll use numpy as an example. (numpy, scipy, matplotlib,and probably pandas will be of the most importance to you for data analyses.
Installation of packages for Python is the easiest using pip:
~$ pip install numpy
We'll see use for external packages later on.


Next: Initializing Newly Added Local Slots (Changing the Class of an Instance), Previous: Changing the Class of an Instance, Up: Changing the Class of an Instance
In order to make the instance conform to the class C_{to}, local slots specified by the class C_{to} that are not specified by the class C_{from} are added, and local slots not specified by the class C_{to} that are specified by the class C_{from} are discarded.
The values of local slots specified by both the class C_{to} and the class C_{from} are retained. If such a local slot was unbound, it remains unbound.
The values of slots specified as shared in the class C_{from} and as local in the class C_{to} are retained.
This first step of the update does not affect the values of any shared slots.


ERROR:
Exception message
Go Back a Page
If you've reached this page when submitting a square, go back and check to see if you:
- Included e's in the width or height
- Submitted a square with more than 20 characters in the name!


Module 01 data-external
This is a slide
Point 1
Point 2
Point 3
This is a second slide
Just to show that you can load multiple slides at a time, this is a second slide.


Antonio Jaggie, professionally known as “Kosten”, is an urban and commercial freelance photographer. Specializing in lifestyle and landscape photography, AJ is known for his powerful, radiant imagery. His inspiration behind the lens can be accredited to the heavy influence of New York City and graffiti culture that he's been entrenched in since a young boy.
“It’s really the thrill of getting a different angle than what most people would ever be able to experience that’s been the main motivator for me.”
At only 20, AJ’s personal works have been recognized and exhibited internationally in various galleries. This mass exposure has led to a cult-like following on Instagram of over 250k followers, gaining substantial coverage from media power houses, such as Business Insider, GQ, High Snobiety and Hypebeast.


scrollutil::plainnotebook
Commandscrollutil::plainnotebook
– Create and manipulate
plainnotebook widgetspackage require scrollutil_tile scrollutil::plainnotebook pathName ?options?
-cursor
-caller pageIndex
-closabletabs
boolean
-forgetcommand
command
-height
screenDistance
-leavecommand
command
-movabletabs
boolean
-side
left|right
-takefocus
0|1|""|command
-title text
-width
screenDistance
pathName add
window ?options?
pathName addbutton
pageIndex text ?image?
pathName addlabel
text ?image?
pathName addseparator
pathName attrib ?name
?value name value ...??
pathName cget
option
pathName closablestate tabId
?boolean?
pathName configure
?option ?value option value ...??
pathName forget
tabId
pathName hasattrib
name
pathName hastabattrib
tabId name
pathName hide
tabId
pathName index
tabId
pathName insert
pos window ?options?
pathName insertbutton
pos pageIndex text ?image?
pathName insertlabel
pos text ?image?
pathName insertseparator pos
pathName instate
stateSpec ?script?
pathName see
tabId
pathName select
?tabId?
pathName state
?stateSpec?
pathName style
pathName tab
tabId ?option ?value option value
...??
pathName tabattrib
tabId ?name ?value name value
...??
pathName tabpath
tabId
pathName tabs
pathName titlepath
pathName unsetattrib
name
pathName unsettabattrib tabId
name
scrollutil::plainnotebook
– Create and manipulate
plainnotebook widgetspackage require scrollutil_tile scrollutil::plainnotebook pathName ?options?
scrollutil::plainnotebook
command is
provided by the Scrollutil_tile package, but not by Scrollutil.scrollutil::plainnotebook
command creates a new
window named pathName
and of the class
Plainnotebook
, and makes it into a plainnotebook
widget. Additional options, described below, may be specified on the
command line or in the option database to configure aspects of the
plainnotebook widget such as its width, height, and side. The
scrollutil::plainnotebook
command returns its
pathName
argument. At the time this command is
invoked, there must not exist a window named pathName
,
but pathName
's parent must exist.see
subcommand. Unlike a ttk::notebook widget
with vertically aligned tabs, which in most themes has a suboptimal look
and whose -height
option is quite often overridden by
the total height of the tabs, the plainnotebook widget respects the value
of its -height
option, regardless
of the space required by the "tabs".-caller
and -title
widget options. The ascend button
displays an image whose shape resembles that of a < character.identify
subcommand, the Tcl command associated with a
plainnotebook widget provides the same subcommands as the one associated
with a ttk::notebook. Note that the API doesn't provide any command
for retrieving the path name of the ttk::notebook widget contained in a
plainnotebook, because there is no need to access that widget
directly. Moreover, using its options or subcommands instead of those
of the plainnotebook widget will more often than not result in an
unpredictable behavior.add
and insert
subcommands are selectable. The ones
created with the plainnotebook-specific subcommands addbutton
and insertbutton
are designed for descending to
another plainnotebook widget, while the ones created via addlabel
, addseparator
, insertlabel
, and insertseparator
can be used as titles and
delimiters of tab groups.-cursor
| Command-Line Name: | -caller |
| Database Name: | caller |
| Database Class: | Caller |
The value of this option must be an integer. If it is nonnegative then the widget's parent must be a pagesman widget. In this case the value is viewed as the numerical index of an already existing page of the parent pagesman widget, and the plainnotebook's ascend button will select that page, which is assumed to be the "caller" of the current plainnotebook widget, meaning that the current plainnotebook was previously selected from within that page. For example, if the option's value is
0
then pressing and later releasing the left mouse button over the ascend button will ascend back to the pagesman page of index0
, which is assumed to be the page from which the user previously descended to the current one. The default is-1
.
| Command-Line Name: | -closabletabs |
| Database Name: | closableTabs |
| Database Class: | ClosableTabs |
Specifies a boolean value that determines whether the tabs created with the
add
andinsert
subcommands (only) will contain theclosebtn
element. This style element is automatically created by the Scrollutil_tile package and is quite similar to theclosetab
element. See the FURTHER BINDINGS section below for details on closing the tabs with the aid of theclosebtn
element. The default is0
. This option can be overridden for individual tabs with the aid of theclosablestate
subcommand.
| Command-Line Name: | -forgetcommand |
| Database Name: | forgetCommand |
| Database Class: | ForgetCommand |
Specifies a command to be invoked when attempting to remove a tab and unmanage the associated window with the aid of the
forget
subcommand. If the option's value is a nonempty string then it is concatenated with the path name of the plainnotebook widget and that of the window to be unmanaged, and the resulting script, which must return a boolean, is evaluated in the global scope. If the return value of this script is false then theforget
subcommand is aborted, i.e., the tab is not removed and the associated window is not unmanaged. The default is an empty string.
| Command-Line Name: | -height |
| Database Name: | height |
| Database Class: | Height |
If present and greater than zero, specifies the desired height of the pane area (not including internal padding) in any of the forms acceptable to
Tk_GetPixels
. Otherwise, the maximum height of all panes is used. The default is0
| Command-Line Name: | -leavecommand |
| Database Name: | leaveCommand |
| Database Class: | LeaveCommand |
Specifies a command to be invoked when attempting to leave the currently selected window by selecting a different one. If the option's value is a nonempty string then it is concatenated with the path name of the plainnotebook widget and that of the currently selected window, and the resulting script, which must return a boolean, is evaluated in the global scope. If the return value of this script is false then the operation of selecting a different window is aborted. The default is an empty string.
| Command-Line Name: | -movabletabs |
| Database Name: | movableTabs |
| Database Class: | MovableTabs |
Specifies a boolean value that determines whether the tabs can be moved with the mouse. See the FURTHER BINDINGS section below for details. The default is
1
.
| Command-Line Name: | -side |
| Database Name: | side |
| Database Class: | Side |
Specifies on which side (
left
orright
) of the widget to show the ttk::frame containing the tabs, the ascend button, and the title label. The default isleft
.
| Command-Line Name: | -takefocus |
| Database Name: | takeFocus |
| Database Class: | TakeFocus |
This option determines whether the plainnotebook widget accepts the focus during keyboard traversal. It is almost identical to the standard option of the same name (see the options manual entry for details). The only difference is that not the plainnotebook widget itself but the scrollableframe contained in it will receive the focus during keyboard traversal with the standard keys (
Tab
andShift-Tab
). The default is"ttk::takefocus"
(just like for ttk::notebook and several other Tk themed widgets).
| Command-Line Name: | -title |
| Database Name: | title |
| Database Class: | Title |
Specifies the text to be displayed in the plainnotebook's title label, which is a ttk::label widget of the style
PnbTitle.TLabel
. The font used for this style is derived fromTkDefaultFont
by increasing the latter's size by a factor of 1.2. To set a different font, use thettk::style
command or retrieve the path name of this widget with thetitlepath
subcommand and then invoke... configure -font ...
.
| Command-Line Name: | -width |
| Database Name: | width |
| Database Class: | Width |
If present and greater than zero, specifies the desired width of the pane area (not including internal padding) in any of the forms acceptable to
Tk_GetPixels
. Otherwise, the maximum width of all panes is used. The default is0
"@x,y
",
the coordinates are expected to be relative to the plainnotebook
window.scrollutil::plainnotebook
command creates a new
Tcl command whose name is pathName
. This
command may be used to invoke various operations on the widget. It
has the following general form:
pathName option ?arg arg ...?
option
and the arg
s determine
the exact behavior of the command. The following commands are
possible for plainnotebook widgets:pathName add window
?options?
window
is currently managed by the notebook but
hidden, the subcommand restores it to its previous position. This
holds equally true for the non-selectable (dummy) windows associated
with the tabs created with the addbutton
, addlabel
, addseparator
, insertbutton
, insertlabel
, and insertseparator
subcommands. If
window
is not yet managed by the notebook then the
corresponding tab will be a ttk::radiobutton widget of a toolbutton
style (Page.Toolbutton
or
ClosablePage.Toolbutton
, depending on the value of the
-closabletabs
option).pathName addbutton
pageIndex text ?image?
Desc.Toolbutton
) that displays, besides the
specified text
and optional
image
, the descend
element,
whose shape resembles that of a > character. This style
element is automatically created by the Scrollutil_tile package.
Its size depends on the display's scaling percentage (100
,
125
, 150
, 175
, or
200
), while its foreground color is theme-specific and is
updated whenever the theme changes. The return value is the path
name of the above-mentioned ttk::button widget.pageIndex
, which must be a nonnegative integer,
specifies the numerical index of a page within the pagesman widget that
will be selected when invoking the toolbutton. It is not expected
that at the time this subcommand is invoked, the page identified by
pageIndex
already exists; it may be created and
added to the pagesman widget later.-caller
option, makes it easy to to write
applications in which the user can descend from a plainnotebook to
another one within a common pagesman parent with a single mouse click
and switch back in the same way to the original one. For example,
if the two plainnotebook widgets have the page indices 0
and 1
then all you need is to pass the page index
1
to the first plainnotebook's
addbutton
subcommand and set the
-caller
option of the second one to the page index
0
.pathName addlabel
text ?image?
PnbLabel.TLabel
that displays the specified
text
and optional image
, and is
typically used as a title of a group of tabs. The font used for
this style is derived from TkDefaultFont
by
increasing the latter's size by a factor of 1.2 and can be changed with
the ttk::style
command. The return value
is the path name of the above-mentioned ttk::label widget; you can use
it, e.g., to override the style's font for this particular label
via ... configure -font ...
.pathName
addseparator
pathName attrib
?name ?value name value ...??
name
is specified, the command returns a list of
pairs, each of which contains the name and the value of an attribute
for pathName
. If name
is
specified with no value
, then the command returns
the value of the one named attribute, or an empty string if no
corresponding value exists (you can use the hasattrib
subcommand to distinguish this
case from the one that the value of an existing attribute is an
empty string). If one or more
name
-value
pairs are specified,
then the command sets the given widget attribute(s) to the given
value(s); in this case the return value is an empty string. Each
name
may be an arbitrary string.pathName cget
option
option
, which may have any of the values accepted
by the scrollutil::plainnotebook
command.pathName
closablestate tabId ?boolean?
closebtn
element in the tab specified by tabId
. The
optional argument is only supported for tabs created via
add
or insert
. This subcommand overrides the
-closabletabs
option for the specified tab.pathName configure
?option ?value option value
...??
option
is specified, the command returns a
list describing all of the available options for
pathName
(see Tk_ConfigureInfo
for information on the format of this list). If
option
is specified with no
value
, then the command returns a list describing
the one named option (this list will be identical to the corresponding
sublist of the value returned if no option
is
specified). If one or more
option
-value
pairs are
specified, then the command modifies the given widget option(s) to have
the given value(s); in this case the return value is an empty
string. option
may have any of the values
accepted by the scrollutil::plainnotebook
command.pathName forget
tabId
pathName hasattrib
name
1
if the attribute name
exists and 0
otherwise.pathName
hastabattrib tabId name
1
if the attribute name
for the tab given by tabId
exists and
0
otherwise.pathName hide
tabId
pathName index
tabId
pathName insert
pos window ?options?
window
is already managed by the notebook, the
subcommand moves it to the specified position. This holds equally
true for the non-selectable (dummy) windows associated with the tabs
created with the addbutton
, addlabel
, addseparator
, insertbutton
, insertlabel
, and insertseparator
subcommands. If
window
is not yet managed by the notebook then the
corresponding tab will be a ttk::radiobutton widget of a toolbutton
style (Page.Toolbutton
or
ClosablePage.Toolbutton
, depending on the value of the
-closabletabs
option).pathName
insertbutton pos pageIndex text
?image?
Desc.Toolbutton
) that displays, besides
the specified text
and optional
image
, the descend
element, at
the specified position. The details are quite similar to the ones
regarding the addbutton
subcommand.pathName
insertlabel pos text ?image?
PnbLabel.TLabel
that displays the specified
text
and optional image
, at the
specified position. The details are quite similar to the ones
regarding the addlabel
subcommand.pathName
insertseparator pos
addseparator
subcommand.pathName instate
stateSpec ?script?
pathName see
tabId
tabId
becomes visible in
it. Note that when a tab gets selected, this command is
automatically invoked for it, in order to make that tab visible.pathName select
?tabId?
pathName state
?stateSpec?
pathName
style
"Plainnotebook.TNotebook"
. For Tk themed widgets
this subcommand was introduced in Tk 8.7a4, but the plainnotebook
widget provides it for all supported Tk versions.pathName tab tabId
?option ?value option value
...??
pathName tabattrib
tabId ?name ?value name value
...??
tabId
. If no name
is
specified, the command returns a list of pairs, each of which contains
the name and the value of an attribute for the tab. If
name
is specified with no
value
, then the command returns the value of the
one named tab attribute, or an empty string if no corresponding value
exists (you can use the hastabattrib
subcommand to distinguish
this case from the one that the value of an existing tab
attribute is an empty string). If one or more
name
-value
pairs are specified,
then the command sets the given tab attribute(s) to the given
value(s); in this case the return value is an empty string. Each
name
may be an arbitrary string.pathName tabpath
tabId
pathName tabs
pathName
titlepath
PnbTitle.TLabel
.pathName
unsetattrib name
name
. Returns an
empty string.pathName
unsettabattrib tabId name
name
for the tab given by
tabId
. Returns an empty string.<<NotebookTabChanged>>
virtual event. This holds true for plainnotebook widgets, too.<<Button3>>
as
<Button-3>
for all windowing systems and
additionally as <Control-Button-1>
for Mac OS
X/11+. If this event occurs over a tab of a plainnotebook whose
disabled
widget state flag is not set, and the Tk
version is 8.5a2 or later, then the widget generates
a <<MenuItemsRequested>>
virtual event,
by invoking event generate
with the
-data
option set to a list consisting of the path
name of an empty pop-up menu and the numerical index of the tab in
question. (The support for this option was introduced in Tk
8.5a2.) If the application creates a binding for this virtual
event, the binding script can access the user data as the value of the
%d
field, with the goal to populate the menu with
application-specific entries. Note that the pop-up menu is posted
with a delay of 100 ms, to make sure that it will appear readily
populated by the application.
The following example provides a pop-up menu item for closing the tabs
of a plainnotebook widget $nb
:
bind $nb <<MenuItemsRequested>> { populateMenu %W %d } proc populateMenu {nb data} { foreach {menu tabIdx} $data {} $menu add command -label "Close Tab" -command [list $nb forget $tabIdx] }
<<NotebookTabMoved>>
and
<<NotebookTabClosed>>
.add
and insert
subcommands. A mouse wheel
tick selects the selectable tab of state normal
cyclically following/preceding the currently selected one. (Note
that the same effect can also be achieved with the keys
Down
, Up
, Control-Tab
, and
Control-Shift-Tab
.) On the windowing system
aqua
, if the Option
key is down while
the mouse wheel is being rotated then a wheel tick selects the 10'th
selectable tab of state normal
cyclically
following/preceding the currently selected one (modulo the number of
selectable tabs). The same holds true on the windowing systems
x11
and win32
if the Tk version
is 8.7a4 or later and the mouse wheel is rotated with the
Alt
key down.closebtn
element
(if any) and then dragged outside that tab then, provided that the
value of the widget's -movabletabs
option is true, the mouse
cursor takes on the shape of an up/down arrow, indicating that the tab
in question is being moved to another position. This operation
ends when mouse button 1 is released, and can be canceled by pressing
the Escape
key. In both cases, the mouse cursor is
reset to its original value, specified by the
-cursor
configuration option. After releasing
mouse button 1, the source tab is moved to the position previously
pointed to by the arrow (provided that the action was not canceled via
Escape
). If the Tk version is 8.5a2 or later then
after moving the tab to its new position, the widget generates a
<<NotebookTabMoved>>
virtual event, by
invoking event generate
with the
-data
option set to a list consisting of the path
name of the widget contained in the source pane and the numerical index
of the target tab position. (The support for this option was
introduced in Tk 8.5a2.)closebtn
element: If mouse button 1 is
pressed over the closebtn
element (if any) of a tab
and later released over the same element then, provided that the value
of the tab's -state
option is
normal
, the tab is closed by means of the widget's
forget
subcommand. Recall that this operation
can get canceled by the command specified as the value of the
-forgetcommand
option;
if this was not the case and the Tk version is 8.5a2 or later then,
after closing the tab, the widget generates a
<<NotebookTabClosed>>
virtual event, by
invoking event generate
with the
-data
option set to the path name of the widget
contained in that tab's pane.disabled
state flag is
set then none of the above actions occur: the tabs are completely
insensitive.


Hi all,
I have an Emontx3 which is working correctly except input 2 is suddenly giving very low readings. All others are correct. I have transferred the CT to another input where it gives the correct readings suggesting a problem with input 2. Are there any other troubleshooting steps I can take before replacing the board which dates back to April 2014?
Re: Emontx3 input showing incorrect readings
If you have a programmer, it's probably worth reloading the sketch. If it's still the same, you could try Robin's Mk2 Code variants and associated tools: http://openenergymonitor.org/emon/node/1757 - both MinAndMaxValues and RawSamplesTool_4ss_2 should be useful - you're looking for a signal centred on 512 or thereabouts.
Other than checking that you have approx 1.65 V dc at the CT input (that's the '512' above), there's probably little you can do unless you have access to an oscilloscope and can check that you have the correct voltage at the analogue input of the processor - you should see 11 mV rms (31 mV p-p) per amp of current, sitting at 1.65 V above ground.
Re: Emontx3 input showing incorrect readings
Hi
I'm having a similar problem. Using the same CT, values are incorrect on CT1 and CT3 and correct on CT2.
I'm using the AC/AC power source
Re: Emontx3 input showing incorrect readings
Webby hasn't come back with any more information, so I think you need to tell me which exact version of emonTx you have, which sketch you are using and exactly how you are measuring and recording the values. Do you have a programmer, and if so, can you try the test sketches I mentioned above?
Re: Emontx3 input showing incorrect readings
I have an EmonTVv3.4 without any radio (using ftdi adapter)
I'm measuring a transformer consumption using a SCT-013-000 clam and comparing to the values of a comercial power metering plug. The plug measures 11W.
I'm using emonTxV3_4_DiscreteSampling from github.
Re: Emontx3 input showing incorrect readings
At 11 W, you really must not expect an accurate reading - that is around 0.05% of the maximum possible reading. If you use a load that is even 1% of maximum, you should get a much better match.
Think of it this way: 11 W = 46 mA primary current in your CT, the secondary current should be 23 μA, giving a peak-peak voltage of 1.4 mV at the ADC input. One ADC sample is 3.3/1024 ≈ 3.3 mV wide. Therefore your input is less than the resolution of the ADC.
Also, even though you're using the same CT, bear in mind that the CT's data sheet states: "Non-linearity ±3% (10%—120% of rated input current)", so even the CT's accuracy is anyone's guess, at that current.
Re: Emontx3 input showing incorrect readings
You are right, moved to metering an dehumidifier (300W) and values show up correctly (+/- 10w).
I just got confused because the value in the CT2 was actually right :)
Thx Robert!
Re: Emontx3 input showing incorrect readings
"the value in the CT2 was actually right"
At the current you had, that was pure luck.


EU Guidelines for Trustworthy AI
Requirements for trustworthy AI from the High-Level expert group on AI setup by the EU Commission.
In order to avoid unintentional harm that improper development of AI technologies can have on the society, the European Commission, through the High-Level expert group on AI, published a series guidelines and checklists for development of trustworthy AI.
By analysing the guidelines, we found out they do not specify actions to be taken by those involved in building AI systems. In order to increase the actionability of the guidelines, we made efforts to extend our catalogue of practices with new practices that address the EU requirements for trustworthy AI.
In particular, we focused on a major sub-field of AI, called machine learning (ML). By analysing the academic and grey literature, we extracted 14 operational practices for trustworthy ML that address the 7 requirements for trustworthy AI from the picture above as follows:
Human agency and oversight
Technical robustness and safety
Privacy and Data Governance
Transparency
- Establish Responsible AI Values
- Inform Users on Machine Learning Usage
- Explain Results and Decisions to Users
- Provide Safe Channels to Raise Concerns
Diversity, Non-Discrimination and Fairness
- Test for Social Bias in Training Data
- Prevent Discriminatory Data Attributes Used As Model Features
- Assess and Manage Subgroup Bias


Some LAPACK eigensystem routines (namely CHEEVR, DSTEVR, DSYEVR, SSTEVR, SSYEVR, ZHEEVR) are able to take advantage of a faster algorithm when the full eigenspectrum is requested on machines which conform to the IEEE-754 floating point standard [14].
Normal execution of the faster algorithm (implemented by LAPACK routines SSTEGR and DSTEGR, which are called by the routines mentioned above) may create NaNs and infinities and hence may abort due to a floating point exception in environments which do not handle NaNs and infinities in the IEEE standard default manner. This may depend upon the compiler flags used to compile and link the main program.
The LAPACK routine ILAENV, called with ISPEC = 10 or 11, states whether or not NaNs or infinities respectively will cause a trap. In ACML, by default ILAENV assumes that NaNs and infinities cause traps, even if this reduces the performance of the eigensystem routines. This is because it is not possible in general to reliably check whether they do trap or not at run-time. The intention is to ensure that these routines always function correctly, irrespective of how the main program calling ACML is compiled.
However, if your main program is compiled in such a way that NaNs and infinities do not cause traps, the ACML-specific routine ILAENVSET (see ILAENV-ILAENVSET) may be used to override the default operative mode of ILAENV, and allow the xxxEVR routines to use the faster xSTEGR algorithm when calculating the full eigenspectrum. When used for this purpose, ILAENVSET should be called as follows:
CALL ILAENVSET(10,'X','X',0,0,0,0,1,INFO) CALL ILAENVSET(11,'X','X',0,0,0,0,1,INFO)
(or the C equivalent).
It is important to note that if you use ILAENVSET in this way before calling an xxxEVR routine, but your program does trap on IEEE exceptions, then there is a chance that your program will terminate unexpectedly. You should consult the documentation for the compiler you are using to find out whether there are compiler flags controlling this.