from this pdf .
Introduction
Magma also contains coding theory functions, including :
Construction of general cyclic codes Construction of standard linear, cyclic, and alternant codes Combining codes : sum, intersection, (external) direct sum, Plotkin sum, concatenation Modifying a code : augment, extend, expurgate, lengthen, puncture, shorten, etc Changing the alphabet : extend field, restrict field, subfield subcode, trace code Construction of basic codes : Hamming, Reed-Muller, Golay, QR Construction of BCH codes and their generalizations : Alternant, BCH, Goppa, Reed-Solomon,
generalized Reed-Solomon, Srivastava, generalized Srivastava Properties : cyclic, self-orthogonal, weakly self-orthogonal, perfect, etc . Minimum weight, words of minimum weight Weight distribution, weight enumerator, MacWilliams transform Complete weight enumerator, MacWilliams transform Coset weight distribution, covering radius, diameter Syndrome decoding, Alternant decoding Bounds : upper and lower bounds on the cardinality of a largest code having given length and
minimum distance Automorphism groups of linear codes over GF(p) (prime p), GF(4) Testing pairs of codes for isomorphism over GF(p) (prime p), GF(4) McEliece Cryptosystem
We demonstrate how these functions can be useful to the cryptographer by implementing the
McEliece public key cryptosystem, and showing an attack on the system when certain precautions
are not taken.
The attack comes from Tom Berson’s Crypto ’97 paper Failure of the McEliece
Public-Key Cryptosystem Under Message-Resend and Related-Message Attack .
Below is the Magma code for implementing this cryptosystem. This code was written by Damien
Fisher, however some small style changes were made.
The first function generates a random Goppa code using the minimal polynomial of a random
element from a degree 50 extension of GF(210). The generator matrix for this code will have
524 rows, 1024 columns, and will be able to correct up to 50 errors. These are the parameters
originally suggested by McEliece.
The function below creates the private and public keys using the RandomCode function. The private
key consists of the tuple < C ; S ; P > where C is the Goppa code, S is an invertible 524 by 524
scrambler matrix, and P is a 1024 by 1024 permutation matrix over GF(2). The public key G is
a 524 by 1024 matrix over GF(2).
function McElieceKey()
// Magically pick C.
C := RandomCode () ;
n := Length (C) ;
k := Dimension (C) ;
M := MatrixRing (GF(2), k) ;
repeat S := Random(M) ; until IsUnit(S) ;
perm := Random (Sym(n)) ;
G := S * GeneratorMatrix (C) ;
I_n := MatrixRing (GF(2), n) !1 ;
P := Parent (I_n) ! [I_n[j] ^ perm : j in [1 .. n]] ;
G := G * P ;
return , G ;
end function ;
Next, we give the functions to encrypt and decrypt. Encryption of a 1024-bit message m is done
by multiplying m (treated as a vector over GF(2)) by G and then adding a random error vector
e having t 1’s in it. Decryption is done by first multiplying the ciphertext by P¡1, then decoding
the Goppa code, and finally multiplying by S^-1.
function McElieceEncrypt (G, m, t)
// Construct a random error vector e of hamming weight t.
n := Ncols (G) ;
V := VectorSpace (GF(2), n) ;
e := Eltseq (Zero(V)) ;
count := 0 ;
repeat
pos := Random (1, n) ;
if (e[pos] eq 0) then
e[pos] := 1 ;
count := count + 1 ;
end if ;
until count eq t ;
return m * G + V !e ;
end function ;
function McElieceDecrypt (x, privKey)
C := privKey[1] ;
S := privKey[2] ;
P := privKey[3] ;
xp := x * (P^-1) ;
succ, mS := Decode (privKey[1], xp) ;
if not succ then
print ("Could not decrypt x !") ;
return mS ;
else
return (InformationSpace(C) ! Coordinates (C, mS)) * S ^ -1 ;
end if ;
end function ;
And now, we test it. This example uses an error of weight t = 10, which is not large enough for
true cryptographic applications, but good enough for illustrative purposes.
> priv, pub := McElieceKey() ;
> m := Random (VectorSpace(GF(2), 524)) ;
> m ;
(0 1 0 0 0 1 1 1 0 1 0 1 0 0 1 1 1 0 0 0 0 1 1 0 1 0 1 0 0 0 0 1 0 0 0 1 1 0 0 1
1 0 1 1 1 0 1 0 0 1 0 1 1 1 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0
1 0 0 1 0 1 0 0 1 1 0 1 1 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1 0 1 1 1 1 0 1 0 1 1
0 0 0 0 0 1 1 1 0 0 1 0 0 1 0 1 1 0 1 0 0 0 0 0 0 1 1 0 1 1 1 1 0 1 1 1 0 0
1 1 0 0 1 1 1 1 1 1 1 0 1 0 1 1 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 0 1 1 0 1 1 0
0 1 0 0 0 1 1 0 0 0 1 0 0 1 0 1 1 0 0 1 0 0 1 0 0 1 1 0 1 1 0 0 1 0 1 1 0 1
0 1 0 1 1 1 1 1 1 0 1 0 1 1 1 0 1 1 1 0 1 1 0 1 1 0 0 0 0 0 0 0 0 1 0 0 1 0
1 1 0 1 0 1 1 0 0 0 0 1 1 1 0 1 0 1 0 0 1 0 1 0 1 1 1 0 1 1 0 0 0 0 0 1 1 0
0 0 0 1 1 0 0 0 1 0 0 1 1 0 0 0 0 0 0 1 0 0 1 1 0 1 0 1 0 1 1 1 1 0 0 0 1 1
1 0 0 1 0 1 0 0 0 1 1 1 1 0 1 1 1 0 1 0 1 0 1 0 1 1 0 1 1 0 0 0 0 0 0 1 0 0
1 0 1 0 1 0 1 0 1 1 0 1 1 1 1 0 0 0 1 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1
1 1 0 0 0 0 1 0 1 0 0 0 1 0 1 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 0 1 1 1 0 0 0 0
1 1 0 1 1 0 1 1 1 1 0 0 1 1 0 1 0 0 1 1 1 1 0 0 1 0 1 1 0 1 1 0 0 0 0 1 1 0
0 0 1 1 0 0 0 0 0 1 1 1 0 1 0 0 1 0 0 0 0 0 0 1 0 1 1 1)
> c := McElieceEncrypt (pub, m, 10) ;
> c ;
(0 0 1 1 0 1 1 0 1 0 0 0 0 1 1 1 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 1 1 1 0 1 0 0
1 0 0 0 0 0 1 1 0 1 1 0 0 0 0 1 1 1 0 0 0 1 0 1 1 1 0 1 1 0 1 0 1 1 1 0 1 1
1 1 0 0 0 1 0 1 1 1 0 1 0 1 0 0 0 1 1 0 0 0 1 0 0 1 1 0 1 1 1 0 1 1 1 1 0 0
1 1 1 1 0 0 0 0 1 1 0 0 1 1 1 0 0 1 1 0 1 1 1 0 0 0 0 1 1 0 0 0 1 1 1 1 1 0
0 0 0 0 1 0 0 0 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 1 1 0 0 1 1 0 1 0 0 0 1 0 1
0 1 1 0 0 0 1 0 0 1 1 1 1 1 0 0 1 0 0 0 1 1 0 0 1 1 0 1 1 1 0 1 1 0 1 0 1 1
1 1 1 1 1 0 0 1 0 0 0 1 0 0 0 0 1 0 1 1 0 0 1 0 1 1 1 0 1 1 1 0 0 0 1 0 0 1
1 1 1 1 1 0 0 0 0 0 1 0 1 1 0 1 1 1 0 1 1 0 0 1 1 1 1 1 0 0 1 0 0 0 0 1 0 1
0 1 1 1 0 1 1 0 1 0 0 1 1 1 0 0 1 1 1 0 0 1 0 0 1 1 0 0 0 0 0 0 0 1 1 0 1 0
0 1 1 0 0 1 0 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 1 0 0 1 1 1 1 1 0 0 1 1 1 1 1 1
0 1 1 0 1 0 1 1 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0
1 1 1 0 1 0 1 1 0 0 1 0 0 0 1 0 1 1 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1
0 1 1 0 0 1 0 0 0 0 0 1 1 1 1 0 1 1 1 1 0 0 0 0 0 0 1 1 0 0 1 0 0 1 0 1 1 1
1 0 0 0 1 1 1 0 1 1 1 0 0 0 1 1 0 0 1 1 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 1 0
1 1 1 1 1 0 0 1 0 1 0 0 0 1 1 1 0 0 0 0 1 1 0 0 0 1 0 1 0 1 1 0 1 1 1 1 0 0
0 0 0 1 0 0 0 0 1 1 0 0 0 1 0 0 1 0 1 1 0 1 1 0 0 0 0 1 1 1 1 0 1 1 1 0 1 0
1 0 1 0 0 1 0 1 1 1 0 1 0 0 0 0 1 0 0 1 1 0 1 0 0 0 0 1 1 0 1 0 0 0 0 1 1 1
0 1 0 1 1 1 0 0 1 1 0 1 0 0 0 1 1 0 0 0 0 1 1 0 0 1 1 1 0 0 1 0 1 0 1 0 0 0
0 0 1 0 1 0 0 1 1 0 0 0 1 0 0 1 1 1 0 1 1 0 0 0 1 1 0 1 1 0 0 1 0 0 1 0 0 1
1 1 0 1 1 1 1 1 0 1 0 1 0 1 0 0 0 1 0 0 0 0 1 0 1 1 1 0 1 0 1 1 0 1 1 1 1 1
0 1 0 1 0 0 0 0 0 1 0 0 0 1 1 0 1 0 0 1 0 0 0 1 1 0 1 0 1 0 1 0 1 1 1 0 1 0
0 0 0 1 1 0 1 0 1 0 0 0 1 1 1 1 0 0 0 1 1 0 1 0 1 0 0 1 0 0 0 1 1 1 0 0 0 0
0 1 0 0 1 1 1 0 0 1 1 1 1 1 0 0 0 0 1 0 1 1 1 0 0 0 0 1 1 1 1 1 0 1 1 1 1 1
1 1 0 0 0 0 0 1 0 0 1 1 0 0 0 1 0 0 0 0 0 0 0 1 1 1 0 1 0 1 1 1 1 0 0 0 1 0
1 0 0 1 0 1 1 0 1 1 0 1 0 1 1 0 1 0 0 0 0 1 1 1 0 1 0 1 0 0 1 1 0 0 1 1 1 1
0 0 1 1 1 1 1 1 1 0 0 0 1 0 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 0 1 1 1 0 1 0 1 1
0 0 0 0 1 0 0 1 0 0 0 0 0 0 1 1 0 1 0 0 0 1 0 1 1 0 0 1 0 0 1 0 1 1)
> mprime := McElieceDecrypt (c, priv) ;
> mprime ;
(0 1 0 0 0 1 1 1 0 1 0 1 0 0 1 1 1 0 0 0 0 1 1 0 1 0 1 0 0 0 0 1 0 0 0 1 1 0 0 1
1 0 1 1 1 0 1 0 0 1 0 1 1 1 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0
1 0 0 1 0 1 0 0 1 1 0 1 1 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1 0 1 1 1 1 0 1 0 1 1
0 0 0 0 0 1 1 1 0 0 1 0 0 1 0 1 1 0 1 0 0 0 0 0 0 1 1 0 1 1 1 1 0 1 1 1 0 0
1 1 0 0 1 1 1 1 1 1 1 0 1 0 1 1 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 0 1 1 0 1 1 0
0 1 0 0 0 1 1 0 0 0 1 0 0 1 0 1 1 0 0 1 0 0 1 0 0 1 1 0 1 1 0 0 1 0 1 1 0 1
0 1 0 1 1 1 1 1 1 0 1 0 1 1 1 0 1 1 1 0 1 1 0 1 1 0 0 0 0 0 0 0 0 1 0 0 1 0
1 1 0 1 0 1 1 0 0 0 0 1 1 1 0 1 0 1 0 0 1 0 1 0 1 1 1 0 1 1 0 0 0 0 0 1 1 0
0 0 0 1 1 0 0 0 1 0 0 1 1 0 0 0 0 0 0 1 0 0 1 1 0 1 0 1 0 1 1 1 1 0 0 0 1 1
1 0 0 1 0 1 0 0 0 1 1 1 1 0 1 1 1 0 1 0 1 0 1 0 1 1 0 1 1 0 0 0 0 0 0 1 0 0
1 0 1 0 1 0 1 0 1 1 0 1 1 1 1 0 0 0 1 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1
1 1 0 0 0 0 1 0 1 0 0 0 1 0 1 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 0 1 1 1 0 0 0 0
1 1 0 1 1 0 1 1 1 1 0 0 1 1 0 1 0 0 1 1 1 1 0 0 1 0 1 1 0 1 1 0 0 0 0 1 1 0
0 0 1 1 0 0 0 0 0 1 1 1 0 1 0 0 1 0 0 0 0 0 0 1 0 1 1 1)
> m eq mprime ;
true
Attacking McEliece using message resend
Following Tom Berson’s article , we explain how to attack the McEliece system when not properly
implemented. The general idea is that if we could guess 524 locations where the product m ∈ G
is not changed by the error vector e, then we can look at those corresponding 524 columns of G
to get a relation that doesn’t involve any error between the ciphertext and the plaintext. If these
columns are linearly independent, then square matrix associated with them can be inverted, and
consequently m can be retrieved.
It takes too much expected work to guess 524 correct columns if nothing is known about where
the errors are. However, if the same message is encrypted twice using different random vectors,
then the exclusive-or of the ciphertexts equals the exclusive-or of the error vectors, hence revealing where most of the errors are. The only errors which are not revealed are those that occur in the
same place for both encryptions. Berson showed that for t = 50, you expect to find around 95.1 of
the 100 errors, and then the probability of correctly guessing 524 good values is very reasonable
(i.e. 5 or 12 attempts is often enough).
Since in our example we are only allowing t = 10, we expect to find approximately 19.8 errors. In
fact, most of the time we will find 20, and this simplifies our code slightly because we usually only
need one attempt.
Here is the Magma code for attacking McEliece under message-resend.
procedure MessageResend()
priv, pub := McElieceKey() ;
n := 1024 ;
k := 524 ;
m := Random (VectorSpace(GF(2), k)) ;
print "original message is : " ;
print m ;
c1 := McElieceEncrypt (pub, m, 10) ;
c2 := McElieceEncrypt (pub, m, 10) ;
c1_plus_c2 := c1 + c2 ;
print "Sum of two ciphertexts is :" ;
print c1 + c2 ;
pubT := Transpose (pub) ;
repeat
/* create a new k by k matrix by selecting certain
columns of pub . To simplify the coding, we actually
work with rows of Transpose (pub) . */
new_mat_seq := [] ;
rows_selected := [] ;
i := 0 ;
one := GF(2) !1 ;
while i lt k do
j := Random (1, n) ;
if c1_plus_c2[j] eq one then
/* don’t select a row corresponding to one of the errors */
continue ;
end if ;
if j in rows_selected then
/* This row has already been selected.
Can’t take it twice */
continue ;
end if ;
/* row j is a keeper */
Append ( rows_selected, j) ;
for l in [1..k] do
Append ( new_mat_seq, pubT[j][l]) ;
end for ;
i + := 1 ;
end while ;
restricted_pub := Transpose (MatrixRing(GF(2), k) !new_mat_seq) ;
until IsUnit (restricted_pub) ;
/* Let c1’ ("c1prime") be the corresponding columns of c1 */
c1prime_seq := [] ;
for i in [1..k] do
Append ( c1prime_seq, c1[rows_selected[i]]) ;
end for ;
c1prime := VectorSpace (GF(2), k) ! c1prime_seq ;
m1prime := c1prime * restricted_pub^-1 ;
if m ne m1prime then
print "deciphering failed." ;
else
print "deciphered message is : " ;
print m1prime ;
end if ;
end procedure ;
Here is a sample output :
> MessageResend() ;
original message is :
(0 0 1 1 0 0 1 0 1 1 1 1 1 0 0 0 0 0 1 1 1 1 0 0 1 0 0 1 0 1 1 1 1 0 0 1 1 1 1 0
0 1 1 1 0 1 0 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 0 1 0 1 0 0 1 0 0 1 1 0 1 0 0
1 1 1 0 1 0 0 1 0 0 0 1 1 0 0 1 0 0 0 1 0 1 1 1 0 0 0 0 1 0 0 1 1 0 0 0 0 0
0 1 0 0 0 1 1 1 0 1 1 0 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 0 0 1 1 0 1 1 1 0 0
1 0 0 1 1 1 1 0 0 0 0 1 0 1 0 0 0 1 1 0 0 1 1 1 1 0 0 1 1 1 1 1 1 0 1 0 1 0
0 0 0 0 1 1 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 1 0 1 1 1 1 1 1 0 1 1 0 1 0 0 1 0
0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 1 1 1 0 0 0 1 0 0 1 1 1 0 1 0 1 0 1 1 0
0 0 0 1 1 0 1 1 1 1 1 1 0 1 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 1 0 0 1 0
1 1 1 1 1 0 1 1 1 1 0 0 1 0 0 1 1 0 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0
1 0 1 0 1 1 1 0 1 0 1 1 0 1 1 0 0 0 0 1 0 0 1 1 0 1 1 1 0 0 1 1 1 0 0 1 0 0
0 1 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 1 0 1 1 1 0 0 0
0 1 1 0 1 1 0 1 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 1 1 1 1 0 1 1 1 0 0 1 1 0 1
0 0 0 0 1 0 1 1 0 1 0 1 1 0 1 0 1 0 1 0 0 0 1 0 1 0 0 1 1 0 0 1 1 1 0 1 1 0
0 0 1 0 0 0 0 0 1 1 1 0 1 0 1 0 0 0 1 1 0 0 1 0 0 0 1 0)
Sum of two ciphertexts is :
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
deciphered message is :
(0 0 1 1 0 0 1 0 1 1 1 1 1 0 0 0 0 0 1 1 1 1 0 0 1 0 0 1 0 1 1 1 1 0 0 1 1 1 1 0
0 1 1 1 0 1 0 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 0 1 0 1 0 0 1 0 0 1 1 0 1 0 0
1 1 1 0 1 0 0 1 0 0 0 1 1 0 0 1 0 0 0 1 0 1 1 1 0 0 0 0 1 0 0 1 1 0 0 0 0 0
0 1 0 0 0 1 1 1 0 1 1 0 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 0 0 1 1 0 1 1 1 0 0
1 0 0 1 1 1 1 0 0 0 0 1 0 1 0 0 0 1 1 0 0 1 1 1 1 0 0 1 1 1 1 1 1 0 1 0 1 0
0 0 0 0 1 1 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 1 0 1 1 1 1 1 1 0 1 1 0 1 0 0 1 0
0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 1 1 1 0 0 0 1 0 0 1 1 1 0 1 0 1 0 1 1 0
0 0 0 1 1 0 1 1 1 1 1 1 0 1 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 1 0 0 1 0
1 1 1 1 1 0 1 1 1 1 0 0 1 0 0 1 1 0 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0
1 0 1 0 1 1 1 0 1 0 1 1 0 1 1 0 0 0 0 1 0 0 1 1 0 1 1 1 0 0 1 1 1 0 0 1 0 0
0 1 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 1 0 1 1 1 0 0 0
0 1 1 0 1 1 0 1 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 1 1 1 1 0 1 1 1 0 0 1 1 0 1
0 0 0 0 1 0 1 1 0 1 0 1 1 0 1 0 1 0 1 0 0 0 1 0 1 0 0 1 1 0 0 1 1 1 0 1 1 0
0 0 1 0 0 0 0 0 1 1 1 0 1 0 1 0 0 0 1 1 0 0 1 0 0 0 1 0)
Notice that the sum of the two ciphertexts had exactly twenty 1’s in it (as expected).